Goals

  1. Perform differential abundance analysis on all cell populations identified from BAL flow by Sasha to identify cell expansion/depletion associated with COVID-19

Setup

Load packages

library(summarytools)
Warning message:
Unknown or uninitialised column: `infection_detected`. 

Google login

drive_auth(use_oob = T, cache = T, email = "rogangrant2022@u.northwestern.edu") # have to run in console :(
Warning messages:
1: Unknown or uninitialised column: `infection_detected`. 
2: Unknown or uninitialised column: `infection_detected`. 

Import Sasha’s data analysis results

data = read_sheet("https://docs.google.com/spreadsheets/d/1KHgJ-ZXQAfgwp-X1U2xjOiYEa--YrR6cGV3U20TxTXo/edit?usp=sharing",
                  skip = 1, 
                  trim_ws = T,
                  .name_repair = "universal")
Reading from "COVID19 BAL stats"
Range "2:5000000"
New names:
* `Length of ICU stay` -> Length.of.ICU.stay
#remove in-progress entries
data = subset(data, !is.na(Sample))

#mark neutrophilic patients
data$neutrophilic = data$percent_neutrophils > 40

#for subsetting later
observations = table(data$ID)
serial_patients = names(observations[observations > 1])

#adjust types
data$ID = as.character(data$ID)

Import clinical metadata

# simple_md = read_excel(path = "~/Box/COVID19_BAL_flow/01_data/02_clinical_metadata/extracted_clinical_data/LMN_extracted_clinical_data_update052020.xlsx",
#                        sheet = "New list",
#                        .name_repair = "universal")
# simple_md$COVID.status = factor(simple_md$COVID.status)
# simple_md$outcome = factor(ifelse(grepl("deceased", simple_md$Discharged..d.c..or.deceased),
#                                   yes = "deceased",
#                                   no = "discharged"))
# simple_md$Study.ID = factor(as.character(simple_md$Study.ID))
# 
# source("~/Documents/GitHub/COVID19_BAL_flow/rgrant/read_clinical_metadata_covid19.R")
# md = read_clinical_metadata_covid19()
# md = subset(md, grepl("\\d{4}-BAL-\\d{2}", Sample..)) #collected samples follow this format
# 
edw_endpoints = read.csv("~/Box/RGrant/SCRIPT/200608 SCRIPT Basic Endpoints.csv",
                         strip.white = T,
                         check.names = T,
                         na.strings = c("", "NA"))
date_cols = colnames(edw_endpoints)[grepl("date", colnames(edw_endpoints), ignore.case = T) |
                                    grepl("\\_dt", colnames(edw_endpoints))]
edw_endpoints = edw_endpoints %>%
  mutate_at(.vars = date_cols,
            .funs = function(x){
              as.Date(x, format = "%m/%d/%y %H:%M", tz = "CST") })
edw_endpoints$pt_study_id = as.character(edw_endpoints$pt_study_id)

#simplify outcome data
edw_endpoints$binned_outcome = factor(vapply(edw_endpoints$discharge_disposition_name,
                                      function(x)
                                      {
                                        if(x == "Expired")
                                        {
                                          return("Deceased")
                                        } else if(grepl("^Home", x))
                                        {
                                          return("Discharged")
                                        } else if(x %in% c("Acute Care Hospital", "Group Home", "Inpatient Hospice",
                                                           "Planned Readmission – DC/transferred to acute inpatient rehab",
                                                           "Acute Inpatient Rehabilitation", "Long-Term Acute Care Hospital (LTAC)",
                                                           "Skilled Nursing Facility or Subacute Rehab Care"))
                                        {
                                          return("Inpatient Facility")
                                        } else if(is.na(x) | x == "unknown")
                                        {
                                          return(as.character(NA))
                                        } else
                                        {
                                          return("Other")
                                        }}, FUN.VALUE = "char"))
edw_endpoints = edw_endpoints %>% 
  select(-full_name)

# edw_micro = read_excel("~/Box/RGrant/SCRIPT/200526 SCRIPT Microbiology BAL Results.xlsx",
#                        skip = 7,
#                        .name_repair = "universal")
# keep_cols = apply(edw_micro, 2, function(x){ !all(is.na(x)) })
# edw_micro = edw_micro[, keep_cols]
# edw_micro$order.datetime = as.Date(edw_micro$order.datetime, origin = "1899-12-30") #excel date format
# edw_micro = subset(edw_micro, !is.na(order.datetime))
# edw_micro$infection_detected = factor(!is.na(edw_micro$organism.name))
# edw_micro$organism.quantity[grepl(">", edw_micro$organism.quantity)] = "10000"
# edw_micro$organism.quantity = as.numeric(edw_micro$organism.quantity)
# #summarize for easy binding, get rid of garbage info
# edw_micro = edw_micro %>% 
#   group_by(pt.study.id, order.datetime) %>% 
#   dplyr::summarize(detected_organisms = list(organism.name),
#             organism_quantities = list(organism.quantity)) %>%
#   rowwise() %>% 
#   mutate(infection_detected = any(!is.na(detected_organisms)))
# 
# #merge all together
# data$sample_id = substring(data$Sample,
#                            10,
#                            20)
# md$Study.ID = as.character(md$Study.ID)
# #need for joining, fixed after
# edw_micro$order.datetime = as.character(edw_micro$order.datetime)
# md$BAL.Date = as.character(md$BAL.Date)
# data = data %>% 
#   left_join(., md, by = c("sample_id" = "Sample..", "ID" = "Study.ID")) %>% 
#   left_join(., simple_md, by = c("ID" = "Study.ID")) %>% 
#   left_join(., edw_endpoints, by = c("ID" = "pt_study_id")) %>% 
#   left_join(., edw_micro, by = c("ID" = "pt.study.id", "BAL.Date" = "order.datetime"))
# only_metadata = md %>% 
#   left_join(., simple_md, by = "Study.ID") %>% 
#   left_join(., edw_endpoints, by = c("Study.ID" = "pt_study_id")) %>% 
#   left_join(., edw_micro, by = c("Study.ID" = "pt.study.id", "BAL.Date" = "order.datetime"))
# only_metadata = unique(only_metadata)
# data$BAL.Date = as.Date(data$BAL.Date)
# edw_micro$order.datetime = as.Date(edw_micro$order.datetime)

#add EDW molecular data   
edw_molecular = read.csv("~/Box/RGrant/SCRIPT/200608 SCRIPT and COVID BAL Results.csv",
                         na.strings = c("", "NA"),
                         strip.white = T,
                         check.names = T) %>% 
  select(-Name)
#make numeric values numeric   
numeric_cols = c("day_of_intubation", "day_of_hospitalization", "RBC_BODY_FLUID", "WBC__BODY_FLUID", "NEUTROPHILS__BODY_FLUID",
                 "Absolute_Neutrophils", "TOXIC_GRANULATION", "MACROPHAGE_BF", "MONOCYTE_BF", "LYMPH_BF", 
                 "ABSOLUTE_LYMPHOCYTES", "EOSINOPHILS__BODY_FLUID", "ABSOLUTE_EOSINOPHILS", "PLASMA_CELL_BF",
                 "OTHER_CELLS__BODY_FLUID", "AMYLASE_BF", "WHITE_BLOOD_CELL_COUNT", 
                 "C_Reactive_Protein", "LDH", "CREATINE_KINASE__TOTAL", "PROCALCITONIN", "FERRITIN", "TROPONIN_I",
                 "Creatinine", "AST__SGOT_", "D_DIMER", "max_daily_temp")
edw_molecular = edw_molecular %>% mutate_at(.vars = numeric_cols, .funs = function(x){
  x = gsub(">", "", x)
  x = gsub("<", "", x)
  x = gsub(",", "", x)
  x = as.numeric(x)
  return(x)})
#fix test columns
test_cols = colnames(edw_molecular)[c(which(colnames(edw_molecular) == "ASPERGILLUS_GALACTOMANNAN_ANTIGEN_NMH_LFH_"):which(colnames(edw_molecular) == "RESPIRATORY_SYNCYTIAL_VIRUS_RESPAN22"),
                                      which(colnames(edw_molecular) == "STREPTOCOCCUS_PNEUMONIAE_ANTIGEN_URINE_1"),
                                      which(colnames(edw_molecular) == "LEGIONELLA_ANTIGEN__EIA__URINE_1"))]
                                            
edw_molecular = edw_molecular %>% mutate_at(.vars = test_cols, 
                                            .funs = function(x){
                                              x = factor(ifelse(is.na(x),
                                                                 yes = NA,
                                                                 no = ifelse((grepl("Not Detected", x, ignore.case = T) |
                                                                                grepl("Negative", x, ignore.case = T)),
                                                                             yes = "Negative",
                                                                             no = "Positive")))
                                                         return(x) })

#remove one strange duplicate entry
edw_molecular = subset(edw_molecular, !(duplicated(paste(edw_molecular$ir_id, edw_molecular$BAL_order_timestamp))))
#format into long form
edw_molecular = edw_molecular %>% 
  pivot_longer(cols = contains("organism_"),
               names_to = "microbiology_parameter",
               values_to = "microbiology_value") 
edw_molecular$main_microbiology_parameter = factor(gsub("_*\\d", "", edw_molecular$microbiology_parameter))
#flatten these parameters into lists of values
edw_molecular = edw_molecular %>%
  group_by(ir_id, BAL_order_timestamp, main_microbiology_parameter) %>%
  mutate(microbiology_value_list = list(microbiology_value)) %>%  # list column
  ungroup() %>% 
  rowwise() %>% 
  mutate_at(.vars = "microbiology_value_list", .funs = function(x){ #remove NA
   cur = na.omit(x)
   if(length(cur) == 0)
   {
     return(list(NULL))
   } else
   {
    return(list(cur))
   }
  }) %>% 
  select(-c(microbiology_parameter, microbiology_value)) %>% 
  ungroup()
#pivot back into wide form for merging (list values get duplicated, need to fix)
listcols = as.character(unique(edw_molecular$main_microbiology_parameter))
edw_molecular = edw_molecular %>%
  pivot_wider(names_from = main_microbiology_parameter,
              values_from = microbiology_value_list) %>% 
  rowwise() %>% 
  #have to remove duplicated list vals
  mutate_at(.vars = listcols, .funs = function(x){ 
              return(list(x[[1]])) }) %>% 
  ungroup()
edw_molecular$order_accession_num = as.character(edw_molecular$order_accession_num)
#fix dates
date_cols = colnames(edw_molecular)[grepl("date", colnames(edw_molecular), ignore.case = T)]
edw_molecular = edw_molecular %>% 
  mutate_at(.vars = date_cols, .funs = function(x){
    as.Date(x, format = "%m/%d/%y", tz = "CST")} )
#make organism quantity numeric
edw_molecular$organism_quantity = lapply(edw_molecular$organism_quantity,
                                         function(x){
                                           x = gsub(">", "", x)
                                           x = gsub("<", "", x)
                                           x = gsub(",", "", x)
                                           x = as.numeric(x)
                                           if(length(x) == 0)
                                           {
                                             return(NULL)
                                           }
                                           return(x)})
                                           

#import BAL data   
edw_BAL = read.csv("~/Box/RGrant/SCRIPT/200608 SCRIPT BAL Related Labs.csv",
                   na.strings = c("", "NA"),
                         strip.white = T,
                         check.names = T) %>% 
  select(c(ir_id, pt_study_id, redcap_bal_dt)) %>% #these columns aren't helpful
  unique()
edw_BAL$pt_study_id = as.character(edw_BAL$pt_study_id)
edw_BAL$redcap_bal_dt = as.Date(edw_BAL$redcap_bal_dt)
colnames(edw_BAL)[colnames(edw_BAL) == "bal_order_date"] = "BAL_order_date"

#import known COVID patients and all patient IDs
covid_cases = read.csv("~/Box/RGrant/SCRIPT/200608 SCRIPT_COVID_list.csv",
                        na.strings = c("", "NA"),
                         strip.white = T,
                         check.names = T,
                       colClasses = rep("character", 5))
covid_cases$covid_confirmed = T
all_patients = read.csv("~/Box/RGrant/SCRIPT/STU00204868_subjects_06_04_2020.csv",
                        na.strings = c("", "NA"),
                         strip.white = T,
                         check.names = T, 
                        colClasses = rep("character", 10)) %>% 
  separate_rows(case.number, sep = ", ") #uncollapse ID column
patient_data = full_join(covid_cases,
                         all_patients,
                         by = c("clarity_west_mrn" = "nmhc_record_number")) %>% 
  select(-c(first_name, last_name, address.line.1:email, nmff_record_number, nmh_record_number,
            first.name, last.name)) #some are duplicated
colnames(patient_data)[colnames(patient_data) == "case.number"] = "study_id"

#merge metadata
edw_molecular$ir_id = as.character(edw_molecular$ir_id)
edw_endpoints$ir_id = as.character(edw_endpoints$ir_id)
only_metadata = left_join(edw_molecular, 
                          patient_data,
                          by = c("ir_id")) %>%
  select(-MRN) %>% 
  full_join(.,
               edw_endpoints,
               by = c("ir_id", "study_id" = "pt_study_id")) %>% 
  select(-west_mrn)

#fix colnames
colnames(data) = gsub("\\.", "_", colnames(data)) #I like underscores
colnames(data) = gsub("_+$", "", colnames(data)) # remove trailing
colnames(data) = gsub("_+", "_", colnames(data)) #remove dup underscores
colnames(only_metadata) = gsub("\\.", "_", colnames(only_metadata)) 
colnames(only_metadata) = gsub("_+$", "", colnames(only_metadata)) 
colnames(only_metadata) = gsub("_+", "_", colnames(only_metadata))

#derive additional metadata
only_metadata$days_from_death = as.numeric(difftime(only_metadata$BAL_order_date, only_metadata$death_date, units = "days"))
only_metadata$covid_confirmed[is.na(only_metadata$covid_confirmed)] = FALSE #may be a safer way to do this
only_metadata$ventilator_days = as.numeric(difftime(only_metadata$BAL_order_date, only_metadata$first_intubation_date, units = "days"))

#merge with flow data
data$sort_date = as.Date(substring(data$Sample, 1, 8), 
                        format = "%Y%m%d")
merge_date = rep(NA, nrow(data))
for(i in 1:nrow(data))
{
  #get patient id and bal order date for each entry
  cur = data[i, ]
  patient = cur$ID
  sort_date = cur$sort_date
  latest = as.Date(sort_date)
  earliest = as.Date(sort_date - 1) #24hr window
  
  #perform matching (should just be one match per)
  matches = subset(only_metadata, 
                   study_id == patient & BAL_order_date >= earliest & BAL_order_date <= latest)
  if(nrow(matches) == 0)
  {
    warning(paste("Unmatched sample warning. Patient:", patient, "Sort date:", sort_date))
    next
  } else if(nrow(matches) > 1)
  {
    stop(paste("Error: mutliple matches for single sample. Patient:", patient, "Sort date:", sort_date))
  } else
  {
    merge_date[i] = as.character(matches$BAL_order_date)
  }
}
data = cbind(data, merge_date)
data$merge_date = as.Date(data$merge_date)

data = left_join(data,
                 only_metadata,
                 by = c("ID" = "study_id", "merge_date" = "BAL_order_date"))

#cast into long form
data = unique(data)
mfi_cols = colnames(data)[grepl("MFI", colnames(data), ignore.case = T)]
percentage_cols = colnames(data)[grepl("percent", colnames(data), ignore.case = T)]
data_long = data %>% 
  pivot_longer(cols = c(mfi_cols, percentage_cols), 
                         names_to = "flow_parameter",
                         values_to = "value") %>% 
  arrange(ID, ventilator_days) #for easy viewing later
data_long$flow_parameter = factor(data_long$flow_parameter)

#output for use with bulk
outname = paste0("~/Box/RGrant/SCRIPT/",
                 Sys.Date(),
                 "_",
                 "SCRIPT_clinical_metadata_processed.rds")
saveRDS(object = only_metadata,
          file = outname)
outname = paste0("~/Box/RGrant/SCRIPT/",
                 Sys.Date(),
                 "_",
                 "SCRIPT_flow_plus_clinical_metadata_processed.rds")
saveRDS(object = data,
          file = outname)

data

Summary stats

Metadata

dfSummary(summary_data, plain.ascii = FALSE, style = "grid", 
          graph.magnif = 0.75, valid.col = FALSE, tmp.img.dir = "/tmp")

Data Frame Summary

summary_data

Dimensions: 869 x 76
Duplicates: 1

No Variable Stats / Values Freqs (% of Valid) Graph Missing
1 ir_id
[character]
1. 2161703
2. 4132754
3. 14931516
4. 1037422
5. 187122
6. 1335514
7. 15023765
8. 1906115
9. 1910810
10. 2211247
[ 507 others ]
14 ( 1.6%)
14 ( 1.6%)
13 ( 1.5%)
9 ( 1.0%)
9 ( 1.0%)
7 ( 0.8%)
7 ( 0.8%)
7 ( 0.8%)
7 ( 0.8%)
7 ( 0.8%)
775 (89.2%)
0
(0%)
2 first_intubation_date
[Date]
min : 2020-03-04
med : 2020-04-16
max : 2020-06-04
range : 3m 0d
87 distinct values 260
(29.92%)
3 hosp_admission_date
[Date]
min : 2020-03-01
med : 2020-04-13
max : 2020-06-04
range : 3m 3d
91 distinct values 254
(29.23%)
4 hosp_disch_date
[Date]
min : 2020-03-21
med : 2020-05-08
max : 2020-06-07
range : 2m 17d
69 distinct values 428
(49.25%)
5 order_accession_num
[character]
1. 12009204212
2. 12006403902
3. 12006502587
4. 12006704644
5. 12006801307
6. 12006802667
7. 12006905404
8. 12006910597
9. 12007004294
10. 12007104458
[ 604 others ]
2 ( 0.3%)
1 ( 0.2%)
1 ( 0.2%)
1 ( 0.2%)
1 ( 0.2%)
1 ( 0.2%)
1 ( 0.2%)
1 ( 0.2%)
1 ( 0.2%)
1 ( 0.2%)
604 (98.2%)
254
(29.23%)
6 BAL_order_timestamp
[character]
1. 6/2/2020 2:08:00 PM
2. 3/22/2020 1:33:00 PM
3. 4/1/2020 4:41:00 PM
4. 4/21/2020 1:33:00 PM
5. 5/16/2020 1:39:00 AM
6. 3/10/2020 10:32:00 AM
7. 3/11/2020 8:40:00 AM
8. 3/12/2020 11:04:00 AM
9. 3/13/2020 5:25:00 PM
10. 3/14/2020 12:49:00 PM
[ 599 others ]
3 ( 0.5%)
2 ( 0.3%)
2 ( 0.3%)
2 ( 0.3%)
2 ( 0.3%)
1 ( 0.2%)
1 ( 0.2%)
1 ( 0.2%)
1 ( 0.2%)
1 ( 0.2%)
599 (97.4%)
254
(29.23%)
7 BAL_order_date
[Date]
min : 2020-03-04
med : 2020-04-24
max : 2020-06-05
range : 3m 1d
93 distinct values 254
(29.23%)
8 procedure_name
[character]
1. CULTURE: RESPIRATORY W/GR
2. CULTURE: RESPIRATORY W/GR
530 (86.2%)
85 (13.8%)
254
(29.23%)
9 day_of_intubation
[numeric]
Mean (sd) : 8.6 (12.3)
min < med < max:
-8 < 4 < 89
IQR (CV) : 12 (1.4)
55 distinct values 260
(29.92%)
10 day_of_hospitalization
[numeric]
Mean (sd) : 10.5 (12.3)
min < med < max:
0 < 7 < 90
IQR (CV) : 13 (1.2)
57 distinct values 254
(29.23%)
11 RBC_BODY_FLUID
[numeric]
Mean (sd) : 8340.9 (24291.6)
min < med < max:
0 < 1687.5 < 331000
IQR (CV) : 5756.5 (2.9)
409 distinct values 361
(41.54%)
12 WBC_BODY_FLUID
[numeric]
Mean (sd) : 1611.5 (4932.9)
min < med < max:
0 < 278 < 53750
IQR (CV) : 753 (3.1)
409 distinct values 326
(37.51%)
13 NEUTROPHILS_BODY_FLUID
[numeric]
Mean (sd) : 58.3 (30)
min < med < max:
0 < 65 < 100
IQR (CV) : 53 (0.5)
101 distinct values 302
(34.75%)
14 Absolute_Neutrophils
[numeric]
Mean (sd) : 10.6 (7.1)
min < med < max:
0 < 9.2 < 52.6
IQR (CV) : 7.9 (0.7)
196 distinct values 394
(45.34%)
15 TOXIC_GRANULATION
[numeric]
All NA’s 869
(100%)
16 MACROPHAGE_BF
[numeric]
Mean (sd) : 18.5 (19.8)
min < med < max:
1 < 10 < 98
IQR (CV) : 23 (1.1)
79 distinct values 348
(40.05%)
17 MONOCYTE_BF
[numeric]
Mean (sd) : 7.5 (8.9)
min < med < max:
0 < 5 < 73
IQR (CV) : 7 (1.2)
38 distinct values 377
(43.38%)
18 LYMPH_BF
[numeric]
Mean (sd) : 13.8 (16.6)
min < med < max:
1 < 6 < 95
IQR (CV) : 16.5 (1.2)
66 distinct values 362
(41.66%)
19 ABSOLUTE_LYMPHOCYTES
[numeric]
Mean (sd) : 1.2 (1)
min < med < max:
0 < 1 < 7.8
IQR (CV) : 0.9 (0.9)
48 distinct values 391
(44.99%)
20 EOSINOPHILS_BODY_FLUID
[numeric]
Mean (sd) : 3.5 (6.2)
min < med < max:
0 < 1 < 40
IQR (CV) : 2 (1.8)
20 distinct values 700
(80.55%)
21 ABSOLUTE_EOSINOPHILS
[numeric]
Mean (sd) : 0.1 (0.2)
min < med < max:
0 < 0 < 1.8
IQR (CV) : 0.2 (1.7)
16 distinct values 390
(44.88%)
22 PLASMA_CELL_BF
[numeric]
Mean (sd) : 6.4 (10)
min < med < max:
0 < 2 < 39
IQR (CV) : 5 (1.6)
13 distinct values 838
(96.43%)
23 OTHER_CELLS_BODY_FLUID
[numeric]
Mean (sd) : 9.6 (14.3)
min < med < max:
0 < 4 < 100
IQR (CV) : 9 (1.5)
45 distinct values 579
(66.63%)
24 AMYLASE_BF
[numeric]
Mean (sd) : 928.4 (5284.2)
min < med < max:
10 < 43 < 85300
IQR (CV) : 149 (5.7)
158 distinct values 553
(63.64%)
25 WHITE_BLOOD_CELL_COUNT
[numeric]
Mean (sd) : 13.3 (8.1)
min < med < max:
0.1 < 11.8 < 58.4
IQR (CV) : 8.8 (0.6)
227 distinct values 262
(30.15%)
26 C_Reactive_Protein
[numeric]
Mean (sd) : 16.5 (11.5)
min < med < max:
0.5 < 15.6 < 52
IQR (CV) : 19 (0.7)
243 distinct values 463
(53.28%)
27 LDH
[numeric]
Mean (sd) : 486.6 (677)
min < med < max:
142 < 372 < 12000
IQR (CV) : 240 (1.4)
306 distinct values 434
(49.94%)
28 CREATINE_KINASE_TOTAL
[numeric]
Mean (sd) : 748.5 (2261.8)
min < med < max:
10 < 164.5 < 20000
IQR (CV) : 412.5 (3)
256 distinct values 525
(60.41%)
29 PROCALCITONIN
[numeric]
Mean (sd) : 6.5 (31.7)
min < med < max:
0 < 0.7 < 482.8
IQR (CV) : 2.6 (4.9)
366 distinct values 407
(46.84%)
30 FERRITIN
[numeric]
Mean (sd) : 1390 (2187.3)
min < med < max:
4.6 < 748.9 < 18123.6
IQR (CV) : 1129.4 (1.6)
343 distinct values 521
(59.95%)
31 TROPONIN_I
[numeric]
Mean (sd) : 0.2 (0.9)
min < med < max:
0 < 0 < 12.7
IQR (CV) : 0.1 (4.6)
60 distinct values 474
(54.55%)
32 Creatinine
[numeric]
Mean (sd) : 1.6 (1.8)
min < med < max:
0.2 < 1.1 < 17.4
IQR (CV) : 1.1 (1.1)
260 distinct values 256
(29.46%)
33 AST_SGOT
[numeric]
Mean (sd) : 92.6 (442.8)
min < med < max:
9 < 42 < 10000
IQR (CV) : 41.2 (4.8)
150 distinct values 297
(34.18%)
34 D_DIMER
[numeric]
Mean (sd) : 3596.9 (6900.3)
min < med < max:
150 < 1166 < 59591
IQR (CV) : 2520.8 (1.9)
382 distinct values 461
(53.05%)
35 max_daily_temp
[numeric]
Mean (sd) : 100.3 (1.7)
min < med < max:
93.1 < 100 < 108.7
IQR (CV) : 2.4 (0)
79 distinct values 255
(29.34%)
36 nmh_mrn
[character]
1. 000666356973
2. 000102901847
3. 000102042781
4. 000103716321
5. 000101880584
6. 000102011706
7. 000700785449
8. 000102209496
9. 000103275513
10. 000666253942
[ 37 others ]
14 (10.6%)
9 ( 6.8%)
7 ( 5.3%)
7 ( 5.3%)
5 ( 3.8%)
5 ( 3.8%)
5 ( 3.8%)
4 ( 3.0%)
4 ( 3.0%)
4 ( 3.0%)
68 (51.5%)
737
(84.81%)
37 clarity_west_mrn
[character]
1. 009285802
2. 008278762
3. 006891929
4. 009451861
5. 111011466718
6. 006678950
7. 007822933
8. 007934943
9. 007261558
10. 007941432
[ 54 others ]
14 ( 8.0%)
9 ( 5.1%)
7 ( 4.0%)
7 ( 4.0%)
7 ( 4.0%)
5 ( 2.8%)
5 ( 2.8%)
5 ( 2.8%)
4 ( 2.3%)
4 ( 2.3%)
109 (61.9%)
693
(79.75%)
38 nmff_mrn
[character]
1. 10219238
2. 08553029
3. 0102042781
4. 10379710
5. 000700785449
6. 08164707
7. 08206840
8. 0353426504
9. 08310911
10. 08370656
[ 37 others ]
14 (10.6%)
9 ( 6.8%)
7 ( 5.3%)
7 ( 5.3%)
5 ( 3.8%)
5 ( 3.8%)
5 ( 3.8%)
4 ( 3.0%)
4 ( 3.0%)
4 ( 3.0%)
68 (51.5%)
737
(84.81%)
39 covid_confirmed
[logical]
1. FALSE
2. TRUE
693 (79.8%)
176 (20.2%)
0
(0%)
40 study
[character]
1. STU00204868 176 (100.0%) 693
(79.75%)
41 study_id
[character]
1. 1255
2. 1248
3. 1270
4. 1271
5. 1286
6. 1232
7. 1266
8. 1292
9. 1224
10. 1230
[ 308 others ]
14 ( 3.3%)
9 ( 2.1%)
7 ( 1.6%)
7 ( 1.6%)
7 ( 1.6%)
5 ( 1.2%)
5 ( 1.2%)
5 ( 1.2%)
4 ( 0.9%)
4 ( 0.9%)
363 (84.4%)
439
(50.52%)
42 birth_date
[character]
1. 1957-12-01
2. 1969-05-01
3. 1958-03-02
4. 1967-09-22
5. 1992-03-02
6. 1933-11-29
7. 1948-01-21
8. 1982-07-30
9. 1944-12-09
10. 1949-11-12
[ 54 others ]
14 ( 8.0%)
9 ( 5.1%)
7 ( 4.0%)
7 ( 4.0%)
7 ( 4.0%)
5 ( 2.8%)
5 ( 2.8%)
5 ( 2.8%)
4 ( 2.3%)
4 ( 2.3%)
109 (61.9%)
693
(79.75%)
43 ethnicity
[character]
1. Hispanic or Latino
2. Not Hispanic or Latino
3. Unknown or Not Reported
72 (40.9%)
89 (50.6%)
15 ( 8.5%)
693
(79.75%)
44 gender
[character]
1. Female
2. Male
65 (36.9%)
111 (63.1%)
693
(79.75%)
45 races
[character]
1. Asian
2. Black/African American
3. Unknown or Not Reported
4. White
4 ( 2.3%)
33 (18.8%)
53 (30.1%)
86 (48.9%)
693
(79.75%)
46 diagnosis
[character]
All NA’s 869
(100%)
47 arms_populations
[character]
All NA’s 869
(100%)
48 uuid
[character]
1. 1eaaa740-6202-0138-e6ac-0
2. 1b8c0890-5c0b-0138-e69a-0
3. 5d6921c0-7471-0138-aba2-0
4. 7f6b0b60-6ad1-0138-e6d6-0
5. f32d8cc0-6af1-0138-e6d6-0
6. 00015530-78e2-0138-abb7-0
7. 372fa3e0-503c-0138-8272-0
8. de908930-6932-0138-e6c4-0
9. 0bab7940-7ab1-0138-abb7-0
10. 1a7fe5d0-4f5e-0138-8272-0
[ 54 others ]
14 ( 8.0%)
9 ( 5.1%)
7 ( 4.0%)
7 ( 4.0%)
7 ( 4.0%)
5 ( 2.8%)
5 ( 2.8%)
5 ( 2.8%)
4 ( 2.3%)
4 ( 2.3%)
109 (61.9%)
693
(79.75%)
49 consent_dt
[Date]
All NA’s 869
(100%)
50 death_date
[Date]
All NA’s 869
(100%)
51 admission_datetime
[Date]
All NA’s 869
(100%)
52 discharge_datetime
[Date]
All NA’s 869
(100%)
53 hospital_los_days
[integer]
Mean (sd) : 26.3 (18.2)
min < med < max:
1 < 23 < 120
IQR (CV) : 22 (0.7)
64 distinct values 510
(58.69%)
54 discharge_disposition_name
[character]
1. Expired
2. Acute Inpatient Rehabilit
3. unknown
4. Home with Home Health Car
5. Home or Self Care
6. Long-Term Acute Care Hosp
7. Skilled Nursing Facility
8. Home with Hospice
9. Home with Outpatient Serv
10. Inpatient Hospice
[ 5 others ]
110 (25.6%)
69 (16.0%)
65 (15.1%)
54 (12.6%)
44 (10.2%)
42 ( 9.8%)
28 ( 6.5%)
6 ( 1.4%)
3 ( 0.7%)
3 ( 0.7%)
6 ( 1.4%)
439
(50.52%)
55 readm_90day_flg
[integer]
1 distinct value 1 : 63 (100.0%) 806
(92.75%)
56 index_icu_start
[character]
1. 3/22/2020 12:00:00 AM
2. 4/18/2020 12:00:00 AM
3. 4/5/2020 12:00:00 AM
4. 4/26/2020 12:00:00 AM
5. 4/29/2020 12:00:00 AM
6. 5/18/2020 12:00:00 AM
7. 4/25/2020 12:00:00 AM
8. 3/12/2020 12:00:00 AM
9. 5/14/2020 12:00:00 AM
10. 5/4/2020 12:00:00 AM
[ 223 others ]
18 ( 4.3%)
14 ( 3.3%)
12 ( 2.8%)
10 ( 2.4%)
10 ( 2.4%)
8 ( 1.9%)
7 ( 1.7%)
6 ( 1.4%)
6 ( 1.4%)
6 ( 1.4%)
325 (77.0%)
447
(51.44%)
57 index_icu_stop
[character]
1. 5/22/2020 12:00:00 AM
2. 3/22/2020 12:00:00 AM
3. 5/18/2020 12:00:00 AM
4. 5/19/2020 12:00:00 AM
5. 5/23/2020 12:00:00 AM
6. 5/28/2020 12:00:00 AM
7. 3/31/2020 12:00:00 AM
8. 4/4/2020 12:00:00 AM
9. 5/21/2020 12:00:00 AM
10. 5/29/2020 12:00:00 AM
[ 220 others ]
39 ( 9.2%)
15 ( 3.6%)
14 ( 3.3%)
10 ( 2.4%)
7 ( 1.7%)
7 ( 1.7%)
6 ( 1.4%)
6 ( 1.4%)
6 ( 1.4%)
6 ( 1.4%)
306 (72.5%)
447
(51.44%)
58 index_ICU_LOS_Days
[integer]
Mean (sd) : 12.7 (11.7)
min < med < max:
1 < 9 < 59
IQR (CV) : 16 (0.9)
39 distinct values 447
(51.44%)
59 total_icu_los_days
[integer]
Mean (sd) : 17.7 (14.8)
min < med < max:
1 < 13 < 84
IQR (CV) : 20 (0.8)
47 distinct values 447
(51.44%)
60 total_num_of_icu_stays
[integer]
Mean (sd) : 1.6 (1.1)
min < med < max:
1 < 1 < 6
IQR (CV) : 1 (0.7)
1 : 286 (67.8%)
2 : 77 (18.2%)
3 : 24 ( 5.7%)
4 : 14 ( 3.3%)
5 : 17 ( 4.0%)
6 : 4 ( 0.9%)
447
(51.44%)
61 icu_readmission_flg
[integer]
1 distinct value 1 : 136 (100.0%) 733
(84.35%)
62 First_intub_start
[character]
1. 3/22/2020 4:00:00 AM
2. 4/6/2020 4:00:00 AM
3. 4/18/2020 12:00:00 PM
4. 4/18/2020 4:00:00 PM
5. 4/26/2020 4:00:00 PM
6. 3/12/2020 12:00:00 PM
7. 4/25/2020 6:30:00 AM
8. 4/29/2020 9:00:00 PM
9. 3/14/2020 11:00:00 AM
10. 3/22/2020 11:39:17 AM
[ 308 others ]
14 ( 3.3%)
9 ( 2.1%)
7 ( 1.6%)
7 ( 1.6%)
7 ( 1.6%)
5 ( 1.2%)
5 ( 1.2%)
5 ( 1.2%)
4 ( 0.9%)
4 ( 0.9%)
363 (84.4%)
439
(50.52%)
63 First_intub_stop
[character]
1. 6/8/2020 5:06:06 PM
2. 3/22/2020 8:30:00 PM
3. 5/18/2020 9:30:00 AM
4. 5/29/2020 2:10:00 PM
5. 5/13/2020 9:00:00 AM
6. 5/28/2020 12:38:00 PM
7. 6/3/2020 10:23:00 PM
8. 3/29/2020 4:00:00 PM
9. 4/19/2020 4:47:00 PM
10. 4/23/2020 3:00:00 AM
[ 294 others ]
42 ( 9.8%)
14 ( 3.3%)
9 ( 2.1%)
7 ( 1.6%)
5 ( 1.2%)
5 ( 1.2%)
5 ( 1.2%)
4 ( 0.9%)
4 ( 0.9%)
4 ( 0.9%)
331 (77.0%)
439
(50.52%)
64 Second_intub_start
[character]
1. 3/27/2020 3:00:00 PM
2. 5/20/2020 10:00:00 PM
3. 3/31/2020 2:00:00 AM
4. 5/9/2020 11:54:00 PM
5. 5/16/2020 4:00:00 PM
6. 6/5/2020 1:00:00 PM
7. 1/10/2019 6:00:00 PM
8. 1/10/2020 7:00:00 PM
9. 1/13/2020 8:00:00 AM
10. 1/16/2020 7:00:00 PM
[ 49 others ]
14 (15.7%)
9 (10.1%)
4 ( 4.5%)
4 ( 4.5%)
3 ( 3.4%)
2 ( 2.2%)
1 ( 1.1%)
1 ( 1.1%)
1 ( 1.1%)
1 ( 1.1%)
49 (55.1%)
780
(89.76%)
65 Second_intub_stop
[character]
1. 3/31/2020 12:00:00 PM
2. 5/21/2020 2:15:00 AM
3. 4/2/2020 10:25:00 PM
4. 5/10/2020 3:22:00 AM
5. 6/2/2020 7:52:00 AM
6. 6/6/2020 9:46:00 AM
7. 1/12/2019 10:00:00 AM
8. 1/13/2020 10:20:00 AM
9. 1/16/2020 10:22:00 PM
10. 1/18/2019 3:56:00 AM
[ 49 others ]
14 (15.7%)
9 (10.1%)
4 ( 4.5%)
4 ( 4.5%)
3 ( 3.4%)
2 ( 2.2%)
1 ( 1.1%)
1 ( 1.1%)
1 ( 1.1%)
1 ( 1.1%)
49 (55.1%)
780
(89.76%)
66 Third_intub_start
[character]
1. 4/3/2020 7:36:00 PM
2. 4/9/2020 4:00:00 AM
3. 6/7/2020 7:53:00 PM
4. 1/16/2019 10:00:00 AM
5. 10/2/2018 2:30:00 AM
6. 11/15/2019 9:00:00 PM
7. 12/10/2018 12:00:00 AM
8. 2/14/2020 12:00:00 AM
9. 2/15/2019 1:45:00 PM
10. 2/20/2020 12:39:00 AM
[ 11 others ]
14 (36.8%)
4 (10.5%)
2 ( 5.3%)
1 ( 2.6%)
1 ( 2.6%)
1 ( 2.6%)
1 ( 2.6%)
1 ( 2.6%)
1 ( 2.6%)
1 ( 2.6%)
11 (28.9%)
831
(95.63%)
67 Third_intub_stop
[character]
1. 5/27/2020 8:00:00 AM
2. 4/13/2020 8:45:00 AM
3. 6/7/2020 8:00:00 PM
4. 1/20/2019 1:00:00 PM
5. 10/6/2018 9:04:00 AM
6. 12/16/2018 9:51:00 AM
7. 12/8/2019 11:44:00 AM
8. 2/14/2020 10:27:00 AM
9. 2/15/2020 8:10:00 AM
10. 2/19/2019 11:00:00 AM
[ 11 others ]
14 (36.8%)
4 (10.5%)
2 ( 5.3%)
1 ( 2.6%)
1 ( 2.6%)
1 ( 2.6%)
1 ( 2.6%)
1 ( 2.6%)
1 ( 2.6%)
1 ( 2.6%)
11 (28.9%)
831
(95.63%)
68 tracheostomy_flg
[integer]
1 distinct value 1 : 77 (100.0%) 792
(91.14%)
69 tracheostomy_dt
[Date]
All NA’s 869
(100%)
70 pt_mech_vent_redcap
[integer]
1 distinct value 1 : 425 (100.0%) 444
(51.09%)
71 days_intube_prior_enroll_redcap
[integer]
Mean (sd) : 10 (70.5)
min < med < max:
0 < 1 < 999
IQR (CV) : 5 (7)
28 distinct values 446
(51.32%)
72 Has_the_patient_had_prior_non_invasive_ventilation_redcap
[integer]
Min : 0
Mean : 0.2
Max : 1
0 : 347 (82.0%)
1 : 76 (18.0%)
446
(51.32%)
73 duration_of_niv_most_recent_redcap
[numeric]
Mean (sd) : 1.3 (2.3)
min < med < max:
0 < 1 < 18
IQR (CV) : 0.8 (1.7)
22 distinct values 793
(91.25%)
74 Has_there_been_more_than_one_episode_of_NIV_redcap
[integer]
Min : 0
Mean : 0.2
Max : 1
0 : 59 (77.6%)
1 : 17 (22.4%)
793
(91.25%)
75 pt_trache_redcap
[integer]
Min : 0
Mean : 0.1
Max : 1
0 : 386 (90.8%)
1 : 39 ( 9.2%)
444
(51.09%)
76 binned_outcome
[factor]
1. Deceased
2. Discharged
3. Inpatient Facility
4. Other
110 (30.1%)
108 (29.6%)
145 (39.7%)
2 ( 0.5%)
504
(58%)

Distributions

Percentages

percentage_data = subset(data_long, grepl("percent", data_long$flow_parameter))
shapiro.test(percentage_data$value)

    Shapiro-Wilk normality test

data:  percentage_data$value
W = 0.77072, p-value < 2.2e-16
hist(percentage_data$value, breaks = 50)

MFIs

mfi_data = subset(data_long, grepl("MFI", data_long$flow_parameter))
shapiro.test(mfi_data$value)

    Shapiro-Wilk normality test

data:  mfi_data$value
W = 0.67565, p-value < 2.2e-16
hist(mfi_data$value, breaks = 50)

Extremely non-normal in both cases. At the very least, we need nonparametric tests. In reality, we probably need non-parametric tests or beta regression. However, this may not be true of individual parameters. First let’s see if transformations help.

Progressions

serial_data = subset(percentage_data, ID %in% serial_patients & 
                       !(flow_parameter %in% c("percent_CD4_total", "percent_CD206_total", "percent_total_CD206_low", "percent_total_CD206_high")))
ggplot(serial_data, aes(x = ventilator_days, y = value, fill = flow_parameter)) +
  geom_bar(position = "stack", stat = "identity") +
  facet_grid(ID ~ .) +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

# ggplot(serial_data, aes(x = days_from_death, y = value, fill = flow_parameter)) +
#   geom_bar(position = "stack", stat = "identity") +
#   facet_grid(ID ~ .) +
#   theme(axis.text.x = element_text(angle = 45, hjust = 1))
# ggplot(serial_data, aes(x = days_from_extubation, y = value, fill = flow_parameter)) +
#   geom_bar(position = "stack", stat = "identity") +
#   facet_grid(ID ~ .) +
#   theme(axis.text.x = element_text(angle = 45, hjust = 1))

As expected, there appear to be neutrophilic and non-neutrophilic trajectories captured here.

Plot contributions (just day 0 for now)

day0_percentages = subset(percentage_data, ventilator_days == 0 &
                            !(flow_parameter %in% c("percent_CD4_total", "percent_CD206_total", "percent_total_CD206_low", "percent_total_CD206_high")))
ggplot(day0_percentages, aes(x = ID, y = value, fill = flow_parameter)) +
  geom_bar(position = "stack", stat = "identity") +
  facet_grid(. ~ covid_confirmed, scales = "free_x") +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

Transformations

Percentages

Arcsine

hist(asin(sqrt(percentage_data$value)), breaks = 50)
NaNs produced

shapiro.test(asin(sqrt(percentage_data$value)))
NaNs produced

    Shapiro-Wilk normality test

data:  asin(sqrt(percentage_data$value))
W = 0.96828, p-value = 0.0009785

Getting there!

Logit

hist(car::logit(percentage_data$value), breaks = 50)

shapiro.test(car::logit(percentage_data$value))

    Shapiro-Wilk normality test

data:  car::logit(percentage_data$value)
W = 0.99734, p-value = 0.1015

This is getting very close. Let’s see if individual observations are normal.

Individual parameters

percentage_data$logit = car::logit(percentage_data$value)
percentage_data %>%
  group_by(flow_parameter) %>% 
  dplyr::summarize(pval = shapiro.test(logit)$p.value)   
`summarise()` ungrouping output (override with `.groups` argument)
ggplot(percentage_data, aes(x = logit)) +
  geom_histogram() +
  facet_wrap(~ flow_parameter)

We can probably work with this, actually. Ideally we should talk to a statistician at some point before publication. Use normalized values for all stats.

MFIs

Log transform

hist(log10(mfi_data$value), breaks = 50)
NaNs produced

shapiro.test(log10(mfi_data$value))
NaNs produced

    Shapiro-Wilk normality test

data:  log10(mfi_data$value)
W = 0.96945, p-value = 1.571e-10

Trimodal? But within individual parameters this should be okay. .

Individual parameters

mfi_data$log10 = log10(mfi_data$value)
NaNs produced
mfi_data %>%
  group_by(flow_parameter) %>% 
  dplyr::summarize(pval = shapiro.test(log10)$p.value)   
`summarise()` ungrouping output (override with `.groups` argument)
ggplot(mfi_data, aes(x = log10)) +
  geom_histogram() +
  facet_wrap(~ flow_parameter)

Looks pretty good.

Analysis

MANCOVA (percentages)

data_wide_percentage = percentage_data %>% 
  pivot_wider(names_from = flow_parameter, 
              values_from = c(logit, value))
data_wide_percentage$covid_confirmed[is.na(data_wide_percentage$covid_confirmed)] = FALSE
data_wide_percentage$covid_confirmed = factor(data_wide_percentage$covid_confirmed)
data_wide_percentage$response = data_wide_percentage %>% 
  select(logit_percent_CD4_total:logit_percent_others)
mancova_data = data_wide_percentage %>% 
  select(c(logit_percent_CD4_total:logit_percent_others, 
           covid_confirmed, ventilator_days)) %>% 
  na.omit()
mancova_fit = manova(cbind(logit_percent_CD4_total, logit_percent_CD4_Tregs, logit_percent_CD4_non_Tregs,
                           logit_percent_CD8_total, logit_percent_CD206_total,  logit_percent_macs_CD206_high,
                           logit_percent_total_CD206_high,  logit_percent_macs_CD206_low, logit_percent_total_CD206_low,
                           logit_percent_neutrophils, logit_percent_monocytes, logit_percent_others) 
                     ~ covid_confirmed * Outcomes,
                     na.action = "na.omit",
                     data = mancova_data) #add outcomes??
summary.aov(mancova_fit)

These are interesting results! With the exception of monocytes, abundance of all cells is affected by COVID-19 in some way. For CD4T, and CD8T, this appears to be purely a main effect. For Tregs and putative MoAM, there is also an interaction effect of day and infection. For TRAM, there is only an interaction effect.

Visualize

Area plot

area_data = percentage_data %>% 
  group_by(covid_confirmed, Day, flow_parameter) %>% 
  dplyr::summarize(mean_pct = mean(value))
`summarise()` regrouping output by 'covid_confirmed', 'Day' (override with `.groups` argument)
area_data = subset(area_data, !(flow_parameter %in% c("percent_CD4_total", "percent_CD206_total", "percent_total_CD206_low", "percent_total_CD206_high")))
ggplot(area_data, aes(x = Day, y = mean_pct, fill = flow_parameter)) +
  geom_area(alpha = 0.7) +
  facet_grid(covid_confirmed ~ .)

This give a false impression between samples. A line plot may actually be better.

Line plot

Grouped

ggplot(percentage_data, aes(x = ventilator_days, y = value, color = flow_parameter)) +
  stat_summary(fun = mean, geom = "line") +
  stat_summary(fun.data = mean_se, geom = "errorbar", width = 0.5, alpha = 0.5) +
  facet_grid(Outcomes ~ covid_confirmed)

By patient

ggplot(percentage_data, aes(x = ventilator_days, y = value, color = flow_parameter)) +
  geom_line() +
  facet_wrap(~ ID)

Not enough data at this point to glean much of anything.

Heatmaps of flow parameters

D0

#cast into matrix of patient x flow parameter
all_day0 = subset(data, ventilator_days == 0)
matrix_data = reshape2::dcast(data = subset(data_long, ventilator_days == 0),
                              formula = ID ~ flow_parameter) %>% 
  column_to_rownames(var = "ID") #easier than removing columns
annotation_data = all_day0 %>% 
  select(c(ID, Outcomes, covid_confirmed)) %>% 
  column_to_rownames(var = "ID")

pheatmap(mat = matrix_data, 
         cluster_rows = T,
         cluster_cols = T,
         clustering_method = "ward.D2",
         annotation_row = annotation_data,
         scale = "column",
         angle_col = 45,
         breaks = seq(-3, 3, length.out=101),
         color = colorRampPalette(rev(brewer.pal(n = 7, name = "RdBu")))(101))

All days

matrix_data = reshape2::dcast(data = data_long,
                              formula = sample_id ~ flow_parameter) %>% 
  column_to_rownames(var = "sample_id")  #easier than removing columns
annotation_data = data %>% 
  select(c(sample_id, outcome, COVID_status, ID, ventilator_days)) %>% 
  column_to_rownames(var = "sample_id")

pheatmap(mat = matrix_data, 
         cluster_rows = T,
         cluster_cols = T,
         clustering_method = "ward.D2",
         annotation_row = annotation_data,
         scale = "column",
         angle_col = 45,
         show_rownames = F,
         breaks = seq(-3, 3, length.out=101),
         color = colorRampPalette(rev(brewer.pal(n = 7, name = "RdBu")))(101))

pheatmap(mat = matrix_data, 
         cluster_rows = F,
         cluster_cols = T,
         clustering_method = "ward.D2",
         annotation_row = annotation_data,
         scale = "column",
         angle_col = 45,
         show_rownames = F,
         breaks = seq(-3, 3, length.out=101),
         color = colorRampPalette(rev(brewer.pal(n = 7, name = "RdBu")))(101))

Co-infection

Proportion of microbe-infected individuals

Plot

only_metadata = only_metadata %>%
  rowwise() %>% 
  mutate(infection_detected = !is.null(organism_name)) %>% 
  ungroup()
only_metadata$infection_detected[is.na(only_metadata$infection_detected)] = "Not Tested"
only_metadata$infection_detected = factor(only_metadata$infection_detected,
                                      levels = c("Not Tested", "TRUE", "FALSE"))
ggplot(subset(only_metadata, !is.na(covid_confirmed)), aes(x = covid_confirmed, fill = infection_detected)) +
  geom_bar(position = "fill") +
  ylab("Proportion") +
  scale_fill_manual(values = c("Not Tested" = "gray", "FALSE" = "cornflowerblue", "TRUE" = "firebrick"))

Levels of infection

Histograms of smear quantities

covid_organism_levels = only_metadata %>% 
  dplyr::filter(covid_confirmed == T) %>% 
  select(organism_quantity) %>% 
  unlist()
other_organism_levels = only_metadata %>% 
  dplyr::filter(covid_confirmed == F) %>% 
  select(organism_quantity) %>% 
  unlist()
ggplot(NULL) +
  geom_density(aes(x = covid_organism_levels), fill = "firebrick", alpha = 0.5) +
  geom_density(aes(x = other_organism_levels), fill = "cornflowerblue", alpha = 0.5)

Infection type

Word cloud

covid_organisms = as.character(only_metadata %>% 
  dplyr::filter(covid_confirmed == T) %>% 
  select(organism_name) %>% 
  unlist() %>% 
  na.omit())
covid_organisms = gsub("[[:punct:]] | | [[:punct:]]|[[:punct:]]", "_", trimws(covid_organisms)) #so we can treat as one word
covid_organisms = gsub("_$", "", covid_organisms)

other_organisms = as.character(only_metadata %>%
                                 dplyr::filter(covid_confirmed == F) %>% 
                                 select(organism_name) %>% 
                                 unlist() %>% 
                                 na.omit())
other_organisms = gsub("[[:punct:]] | | [[:punct:]]|[[:punct:]]", "_", trimws(other_organisms))
other_organisms = gsub("_$", "", other_organisms)

#make into data frame with normalized freqs
df1 = data.frame(word = names(termFreq(covid_organisms)),
                 freq = as.numeric(termFreq(covid_organisms)) / 
                                     sum(as.numeric(termFreq(covid_organisms))),
                 covid_confirmed = T)
df2 = data.frame(word = names(termFreq(other_organisms)),
                 freq = as.numeric(termFreq(other_organisms)) /
                                     sum(as.numeric(termFreq(other_organisms))),
                 covid_confirmed = F)

#finally, plot
wordcould_df = rbind(df1, df2)
ggplot(wordcould_df, aes(label = word, size = freq)) +
  geom_text_wordcloud(show.legend = F) +
  facet_wrap(~ covid_confirmed)

Factor analysis

Subset to usable factors

clinical_data = only_metadata %>% 
  unique() %>% #oddly there is duplication
  dplyr::filter(!is.na(BAL_order_date)) %>% #remove samples without BAL info
  mutate(sample_id = paste(ir_id, BAL_order_timestamp, sep = "_")) %>% 
  select(c(sample_id,
           RBC_BODY_FLUID:Absolute_Neutrophils,
           MACROPHAGE_BF:OTHER_CELLS_BODY_FLUID,
           AMYLASE_BF,
           WHITE_BLOOD_CELL_COUNT:D_DIMER, 
           max_daily_temp)) %>% 
    column_to_rownames(var = "sample_id")

PCA

Calculation

safe_cols = function(x)
{
  return(all(is.finite(na.omit(x))) & 
           sd(x, na.rm = T) > 0 &
           sum(!is.na(x)) > (length(x) / 2))
}
keep_cols = apply(clinical_data, 2, safe_cols)
pca_data = na.omit(clinical_data[, keep_cols])

#need to use formula interface to deal with NAs because nothing is ever easy
formula = paste0("~ ",
                 paste(colnames(pca_data), collapse = "+"))
formula = as.formula(formula)
pca = prcomp(formula = formula,
             data = pca_data, 
             scale. = T,
             na.action = na.omit)

pca_data_complete = only_metadata %>% 
  unique() %>%
  mutate(sample_id = paste(ir_id, BAL_order_timestamp, sep = "_")) %>% 
  dplyr::filter(sample_id %in% rownames(pca_data)) %>% 
  column_to_rownames(var = "sample_id")

Screeplot

fviz_eig(pca)

Biplot

autoplot(pca, 
There were 34 warnings (use warnings() to see them)
         data = pca_data_complete, 
         colour = "binned_outcome",
         shape = "covid_confirmed",
         loadings = TRUE, 
         loadings.colour = alpha("blue", 0.1),
         loadings.label = TRUE, 
         loadings.label.size = 2,
         loadings.label.colour = alpha("red", 0.7),
         x = 1,
         y = 2)

autoplot(pca, 
         data = pca_data_complete, 
         colour = "binned_outcome",
         shape = "covid_confirmed",
         loadings = TRUE, 
         loadings.colour = alpha("blue", 0.1),
         loadings.label = TRUE, 
         loadings.label.size = 2,
         loadings.label.colour = alpha("red", 0.7),
         x = 2,
         y = 3)

autoplot(pca, 
         data = pca_data_complete, 
         colour = "binned_outcome",
         shape = "covid_confirmed",
         loadings = TRUE, 
         loadings.colour = alpha("blue", 0.1),
         loadings.label = TRUE, 
         loadings.label.size = 2,
         loadings.label.colour = alpha("red", 0.7),
         x = 3,
         y = 4)

Some interesting loadings: PC1-2 is driven heavily by markers of sepsis and/or organ failure. PC3 appears to just broadly be immune response, but I find it interesting that CRP and monocytes (in this case from BAL) travel together. Are they the source of IL6? Is this a response to IL6? PC4 is similar, with influence of CRP and ferritin suggesting high levels of inflammation. Let’s also try UMAP to see if there is some hidden structure.

Calculation on fewer parameters

clinical_data_ltd = only_metadata %>% 
  unique() %>% #oddly there is duplication
  dplyr::filter(!is.na(BAL_order_date)) %>% #remove samples without BAL info
  mutate(sample_id = paste(ir_id, BAL_order_timestamp, sep = "_")) %>% 
  select(c(sample_id,
           Absolute_Neutrophils,
           WHITE_BLOOD_CELL_COUNT:D_DIMER, 
           max_daily_temp)) %>% 
    column_to_rownames(var = "sample_id")

keep_cols = apply(clinical_data_ltd, 2, safe_cols)
pca_data = na.omit(clinical_data_ltd[, keep_cols])

#need to use formula interface to deal with NAs because nothing is ever easy
formula = paste0("~ ",
                 paste(colnames(pca_data), collapse = "+"))
formula = as.formula(formula)
pca = prcomp(formula = formula,
             data = pca_data, 
             scale. = T,
             na.action = na.omit)

pca_data_complete = only_metadata %>% 
  unique() %>%
  mutate(sample_id = paste(ir_id, BAL_order_timestamp, sep = "_")) %>% 
  dplyr::filter(sample_id %in% rownames(pca_data)) %>% 
  column_to_rownames(var = "sample_id")

Biplot

autoplot(pca, 
         data = pca_data_complete, 
         colour = "binned_outcome",
         loadings = TRUE, 
         loadings.colour = alpha("blue", 0.1),
         loadings.label = TRUE, 
         loadings.label.size = 2,
         loadings.label.colour = alpha("red", 0.7),
         x = 1,
         y = 2)

autoplot(pca, 
         data = pca_data_complete, 
         colour = "binned_outcome",
         loadings = TRUE, 
         loadings.colour = alpha("blue", 0.1),
         loadings.label = TRUE, 
         loadings.label.size = 2,
         loadings.label.colour = alpha("red", 0.7),
         x = 2,
         y = 3)

autoplot(pca, 
         data = pca_data_complete, 
         colour = "binned_outcome",
         loadings = TRUE, 
         loadings.colour = alpha("blue", 0.1),
         loadings.label = TRUE, 
         loadings.label.size = 2,
         loadings.label.colour = alpha("red", 0.7),
         x = 3,
         y = 4)

UMAP

Calculate UMAP

umap = umap(pca_data, 
            n_neighbors = 15,
            min_dist = 0.1,
            scale = "Z")
colnames(umap) = c("umap_1", "umap_2")
umap_data = cbind(pca_data_complete, umap)

Plot

This doesn’t seem to add much.

Just D0 samples

autoplot(pca, 
         data = pca_data_complete, 
         colour = "binned_outcome",
         loadings = TRUE, 
         loadings.colour = alpha("blue", 0.1),
         loadings.label = TRUE, 
         loadings.label.size = 2,
         loadings.label.colour = alpha("red", 0.7),
         x = 1,
         y = 2)
autoplot(pca, 
         data = pca_data_complete, 
         colour = "binned_outcome",
         loadings = TRUE, 
         loadings.colour = alpha("blue", 0.1),
         loadings.label = TRUE, 
         loadings.label.size = 2,
         loadings.label.colour = alpha("red", 0.7),
         x = 2,
         y = 3)

autoplot(pca, 
         data = pca_data_complete, 
         colour = "binned_outcome",
         loadings = TRUE, 
         loadings.colour = alpha("blue", 0.1),
         loadings.label = TRUE, 
         loadings.label.size = 2,
         loadings.label.colour = alpha("red", 0.7),
         x = 3,
         y = 4)

Not actually very different from complete dataset.

With flow data

All samples

autoplot(pca, 
         data = pca_data_complete, 
         colour = "binned_outcome",
         loadings = TRUE, 
         loadings.colour = alpha("blue", 0.1),
         loadings.label = TRUE, 
         loadings.label.size = 2,
         loadings.label.colour = alpha("red", 0.7),
         x = 1,
         y = 2)
autoplot(pca, 
         data = pca_data_complete, 
         colour = "binned_outcome",
         loadings = TRUE, 
         loadings.colour = alpha("blue", 0.1),
         loadings.label = TRUE, 
         loadings.label.size = 2,
         loadings.label.colour = alpha("red", 0.7),
         x = 2,
         y = 3)

autoplot(pca, 
         data = pca_data_complete, 
         colour = "binned_outcome",
         loadings = TRUE, 
         loadings.colour = alpha("blue", 0.1),
         loadings.label = TRUE, 
         loadings.label.size = 2,
         loadings.label.colour = alpha("red", 0.7),
         x = 3,
         y = 4)

Data is still too sparse to really look into this.

Hierarchical clustering

All days

heatmap_data = only_metadata %>% 
Warning message:
Unknown or uninitialised column: `infection_detected`. 
  unique() %>% #oddly there is duplication
  dplyr::filter(!is.na(BAL_order_date)) %>% #remove samples without BAL info
  mutate(sample_id = paste(ir_id, BAL_order_timestamp, sep = "_")) %>% 
  select(c(sample_id,
           Absolute_Neutrophils,
           WHITE_BLOOD_CELL_COUNT:D_DIMER, 
           max_daily_temp)) %>% 
    column_to_rownames(var = "sample_id")

heatmap_metadata = only_metadata %>% 
  unique() %>%
  mutate(sample_id = paste(ir_id, BAL_order_timestamp, sep = "_")) %>% 
  dplyr::filter(sample_id %in% rownames(heatmap_data)) %>% 
  select(sample_id, ventilator_days, binned_outcome) %>% 
  column_to_rownames(var = "sample_id")

pheatmap(heatmap_data, 
         cluster_rows = T,
         cluster_cols = T,
         clustering_method = "ward.D2",
         annotation_row = heatmap_metadata,
         scale = "column",
         angle_col = 45,
         breaks = seq(-5, 5, length.out=101),
         color = colorRampPalette(rev(brewer.pal(n = 7, name = "RdBu")))(101))

LS0tCnRpdGxlOiAiU0NSSVBUIEZsb3cgREFBIgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIGRmX3ByaW50OiBwYWdlZAotLS0KCiMjIEdvYWxzICAgCjEuIFBlcmZvcm0gZGlmZmVyZW50aWFsIGFidW5kYW5jZSBhbmFseXNpcyBvbiBhbGwgY2VsbCBwb3B1bGF0aW9ucyBpZGVudGlmaWVkIGZyb20gQkFMIGZsb3cgYnkgU2FzaGEgdG8gaWRlbnRpZnkgY2VsbCBleHBhbnNpb24vZGVwbGV0aW9uIGFzc29jaWF0ZWQgd2l0aCBDT1ZJRC0xOSAgIAogICAKIyBTZXR1cCAgIAojIyBMb2FkIHBhY2thZ2VzICAgCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShnb29nbGVzaGVldHM0KQpsaWJyYXJ5KGdvb2dsZWRyaXZlKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShzdW1tYXJ5dG9vbHMpCmxpYnJhcnkoY2FyKQpsaWJyYXJ5KEhtaXNjKQpsaWJyYXJ5KHJlYWR4bCkKbGlicmFyeShnZ2ZvcnRpZnkpCmxpYnJhcnkoZmxvd0NvcmUpCmxpYnJhcnkobHVicmlkYXRlKQpsaWJyYXJ5KHJlc2hhcGUyKQpsaWJyYXJ5KHBoZWF0bWFwKQpsaWJyYXJ5KFJDb2xvckJyZXdlcikKbGlicmFyeShnZ3dvcmRjbG91ZCkKbGlicmFyeSh0bSkKbGlicmFyeShmYWN0b2V4dHJhKQpsaWJyYXJ5KHV3b3QpCmxpYnJhcnkoaWdyYXBoKQoKbWVhbl9zZCA9IGZ1bmN0aW9uKHgpewogIHJldHVybihtZWFuX3NkbCh4LCBtdWx0ID0gMSkpCn0KCnNldC5zZWVkKDEyMzQ1KQpgYGAKICAgCiMjIEdvb2dsZSBsb2dpbiAgIApgYGB7cn0KZHJpdmVfYXV0aCh1c2Vfb29iID0gVCwgY2FjaGUgPSBULCBlbWFpbCA9ICJyb2dhbmdyYW50MjAyMkB1Lm5vcnRod2VzdGVybi5lZHUiKSAjIGhhdmUgdG8gcnVuIGluIGNvbnNvbGUgOigKZ3M0X2F1dGgodG9rZW4gPSBkcml2ZV90b2tlbigpLCB1c2Vfb29iID0gVCwgY2FjaGUgPSBULCBlbWFpbCA9ICJyb2dhbmdyYW50MjAyMkB1Lm5vcnRod2VzdGVybi5lZHUiKQpgYGAKCiAgIAojIyBJbXBvcnQgU2FzaGEncyBkYXRhIGFuYWx5c2lzIHJlc3VsdHMgICAKYGBge3J9CmRhdGEgPSByZWFkX3NoZWV0KCJodHRwczovL2RvY3MuZ29vZ2xlLmNvbS9zcHJlYWRzaGVldHMvZC8xS0hnSi1aWFFBZmd3cC1YMVUyeGpPaVlFYS0tWXJSNmNHVjNVMjBUeFRYby9lZGl0P3VzcD1zaGFyaW5nIiwKICAgICAgICAgICAgICAgICAgc2tpcCA9IDEsIAogICAgICAgICAgICAgICAgICB0cmltX3dzID0gVCwKICAgICAgICAgICAgICAgICAgLm5hbWVfcmVwYWlyID0gInVuaXZlcnNhbCIpCgojcmVtb3ZlIGluLXByb2dyZXNzIGVudHJpZXMKZGF0YSA9IHN1YnNldChkYXRhLCAhaXMubmEoU2FtcGxlKSkKCiNtYXJrIG5ldXRyb3BoaWxpYyBwYXRpZW50cwpkYXRhJG5ldXRyb3BoaWxpYyA9IGRhdGEkcGVyY2VudF9uZXV0cm9waGlscyA+IDQwCgojZm9yIHN1YnNldHRpbmcgbGF0ZXIKb2JzZXJ2YXRpb25zID0gdGFibGUoZGF0YSRJRCkKc2VyaWFsX3BhdGllbnRzID0gbmFtZXMob2JzZXJ2YXRpb25zW29ic2VydmF0aW9ucyA+IDFdKQoKI2FkanVzdCB0eXBlcwpkYXRhJElEID0gYXMuY2hhcmFjdGVyKGRhdGEkSUQpCmBgYAogICAKIyMgSW1wb3J0IGNsaW5pY2FsIG1ldGFkYXRhICAgCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMgc2ltcGxlX21kID0gcmVhZF9leGNlbChwYXRoID0gIn4vQm94L0NPVklEMTlfQkFMX2Zsb3cvMDFfZGF0YS8wMl9jbGluaWNhbF9tZXRhZGF0YS9leHRyYWN0ZWRfY2xpbmljYWxfZGF0YS9MTU5fZXh0cmFjdGVkX2NsaW5pY2FsX2RhdGFfdXBkYXRlMDUyMDIwLnhsc3giLAojICAgICAgICAgICAgICAgICAgICAgICAgc2hlZXQgPSAiTmV3IGxpc3QiLAojICAgICAgICAgICAgICAgICAgICAgICAgLm5hbWVfcmVwYWlyID0gInVuaXZlcnNhbCIpCiMgc2ltcGxlX21kJENPVklELnN0YXR1cyA9IGZhY3RvcihzaW1wbGVfbWQkQ09WSUQuc3RhdHVzKQojIHNpbXBsZV9tZCRvdXRjb21lID0gZmFjdG9yKGlmZWxzZShncmVwbCgiZGVjZWFzZWQiLCBzaW1wbGVfbWQkRGlzY2hhcmdlZC4uZC5jLi5vci5kZWNlYXNlZCksCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHllcyA9ICJkZWNlYXNlZCIsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5vID0gImRpc2NoYXJnZWQiKSkKIyBzaW1wbGVfbWQkU3R1ZHkuSUQgPSBmYWN0b3IoYXMuY2hhcmFjdGVyKHNpbXBsZV9tZCRTdHVkeS5JRCkpCiMgCiMgc291cmNlKCJ+L0RvY3VtZW50cy9HaXRIdWIvQ09WSUQxOV9CQUxfZmxvdy9yZ3JhbnQvcmVhZF9jbGluaWNhbF9tZXRhZGF0YV9jb3ZpZDE5LlIiKQojIG1kID0gcmVhZF9jbGluaWNhbF9tZXRhZGF0YV9jb3ZpZDE5KCkKIyBtZCA9IHN1YnNldChtZCwgZ3JlcGwoIlxcZHs0fS1CQUwtXFxkezJ9IiwgU2FtcGxlLi4pKSAjY29sbGVjdGVkIHNhbXBsZXMgZm9sbG93IHRoaXMgZm9ybWF0CiMgCmVkd19lbmRwb2ludHMgPSByZWFkLmNzdigifi9Cb3gvUkdyYW50L1NDUklQVC8yMDA2MDggU0NSSVBUIEJhc2ljIEVuZHBvaW50cy5jc3YiLAogICAgICAgICAgICAgICAgICAgICAgICAgc3RyaXAud2hpdGUgPSBULAogICAgICAgICAgICAgICAgICAgICAgICAgY2hlY2submFtZXMgPSBULAogICAgICAgICAgICAgICAgICAgICAgICAgbmEuc3RyaW5ncyA9IGMoIiIsICJOQSIpKQpkYXRlX2NvbHMgPSBjb2xuYW1lcyhlZHdfZW5kcG9pbnRzKVtncmVwbCgiZGF0ZSIsIGNvbG5hbWVzKGVkd19lbmRwb2ludHMpLCBpZ25vcmUuY2FzZSA9IFQpIHwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JlcGwoIlxcX2R0IiwgY29sbmFtZXMoZWR3X2VuZHBvaW50cykpXQplZHdfZW5kcG9pbnRzID0gZWR3X2VuZHBvaW50cyAlPiUKICBtdXRhdGVfYXQoLnZhcnMgPSBkYXRlX2NvbHMsCiAgICAgICAgICAgIC5mdW5zID0gZnVuY3Rpb24oeCl7CiAgICAgICAgICAgICAgYXMuRGF0ZSh4LCBmb3JtYXQgPSAiJW0vJWQvJXkgJUg6JU0iLCB0eiA9ICJDU1QiKSB9KQplZHdfZW5kcG9pbnRzJHB0X3N0dWR5X2lkID0gYXMuY2hhcmFjdGVyKGVkd19lbmRwb2ludHMkcHRfc3R1ZHlfaWQpCgojc2ltcGxpZnkgb3V0Y29tZSBkYXRhCmVkd19lbmRwb2ludHMkYmlubmVkX291dGNvbWUgPSBmYWN0b3IodmFwcGx5KGVkd19lbmRwb2ludHMkZGlzY2hhcmdlX2Rpc3Bvc2l0aW9uX25hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24oeCkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZih4ID09ICJFeHBpcmVkIikKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuKCJEZWNlYXNlZCIpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYoZ3JlcGwoIl5Ib21lIiwgeCkpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybigiRGlzY2hhcmdlZCIpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYoeCAlaW4lIGMoIkFjdXRlIENhcmUgSG9zcGl0YWwiLCAiR3JvdXAgSG9tZSIsICJJbnBhdGllbnQgSG9zcGljZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlBsYW5uZWQgUmVhZG1pc3Npb24g4oCTIERDL3RyYW5zZmVycmVkIHRvIGFjdXRlIGlucGF0aWVudCByZWhhYiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkFjdXRlIElucGF0aWVudCBSZWhhYmlsaXRhdGlvbiIsICJMb25nLVRlcm0gQWN1dGUgQ2FyZSBIb3NwaXRhbCAoTFRBQykiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTa2lsbGVkIE51cnNpbmcgRmFjaWxpdHkgb3IgU3ViYWN1dGUgUmVoYWIgQ2FyZSIpKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4oIklucGF0aWVudCBGYWNpbGl0eSIpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYoaXMubmEoeCkgfCB4ID09ICJ1bmtub3duIikKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuKGFzLmNoYXJhY3RlcihOQSkpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2UKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuKCJPdGhlciIpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9fSwgRlVOLlZBTFVFID0gImNoYXIiKSkKZWR3X2VuZHBvaW50cyA9IGVkd19lbmRwb2ludHMgJT4lIAogIHNlbGVjdCgtZnVsbF9uYW1lKQoKIyBlZHdfbWljcm8gPSByZWFkX2V4Y2VsKCJ+L0JveC9SR3JhbnQvU0NSSVBULzIwMDUyNiBTQ1JJUFQgTWljcm9iaW9sb2d5IEJBTCBSZXN1bHRzLnhsc3giLAojICAgICAgICAgICAgICAgICAgICAgICAgc2tpcCA9IDcsCiMgICAgICAgICAgICAgICAgICAgICAgICAubmFtZV9yZXBhaXIgPSAidW5pdmVyc2FsIikKIyBrZWVwX2NvbHMgPSBhcHBseShlZHdfbWljcm8sIDIsIGZ1bmN0aW9uKHgpeyAhYWxsKGlzLm5hKHgpKSB9KQojIGVkd19taWNybyA9IGVkd19taWNyb1ssIGtlZXBfY29sc10KIyBlZHdfbWljcm8kb3JkZXIuZGF0ZXRpbWUgPSBhcy5EYXRlKGVkd19taWNybyRvcmRlci5kYXRldGltZSwgb3JpZ2luID0gIjE4OTktMTItMzAiKSAjZXhjZWwgZGF0ZSBmb3JtYXQKIyBlZHdfbWljcm8gPSBzdWJzZXQoZWR3X21pY3JvLCAhaXMubmEob3JkZXIuZGF0ZXRpbWUpKQojIGVkd19taWNybyRpbmZlY3Rpb25fZGV0ZWN0ZWQgPSBmYWN0b3IoIWlzLm5hKGVkd19taWNybyRvcmdhbmlzbS5uYW1lKSkKIyBlZHdfbWljcm8kb3JnYW5pc20ucXVhbnRpdHlbZ3JlcGwoIj4iLCBlZHdfbWljcm8kb3JnYW5pc20ucXVhbnRpdHkpXSA9ICIxMDAwMCIKIyBlZHdfbWljcm8kb3JnYW5pc20ucXVhbnRpdHkgPSBhcy5udW1lcmljKGVkd19taWNybyRvcmdhbmlzbS5xdWFudGl0eSkKIyAjc3VtbWFyaXplIGZvciBlYXN5IGJpbmRpbmcsIGdldCByaWQgb2YgZ2FyYmFnZSBpbmZvCiMgZWR3X21pY3JvID0gZWR3X21pY3JvICU+JSAKIyAgIGdyb3VwX2J5KHB0LnN0dWR5LmlkLCBvcmRlci5kYXRldGltZSkgJT4lIAojICAgZHBseXI6OnN1bW1hcml6ZShkZXRlY3RlZF9vcmdhbmlzbXMgPSBsaXN0KG9yZ2FuaXNtLm5hbWUpLAojICAgICAgICAgICAgIG9yZ2FuaXNtX3F1YW50aXRpZXMgPSBsaXN0KG9yZ2FuaXNtLnF1YW50aXR5KSkgJT4lCiMgICByb3d3aXNlKCkgJT4lIAojICAgbXV0YXRlKGluZmVjdGlvbl9kZXRlY3RlZCA9IGFueSghaXMubmEoZGV0ZWN0ZWRfb3JnYW5pc21zKSkpCiMgCiMgI21lcmdlIGFsbCB0b2dldGhlcgojIGRhdGEkc2FtcGxlX2lkID0gc3Vic3RyaW5nKGRhdGEkU2FtcGxlLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgIDEwLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgIDIwKQojIG1kJFN0dWR5LklEID0gYXMuY2hhcmFjdGVyKG1kJFN0dWR5LklEKQojICNuZWVkIGZvciBqb2luaW5nLCBmaXhlZCBhZnRlcgojIGVkd19taWNybyRvcmRlci5kYXRldGltZSA9IGFzLmNoYXJhY3RlcihlZHdfbWljcm8kb3JkZXIuZGF0ZXRpbWUpCiMgbWQkQkFMLkRhdGUgPSBhcy5jaGFyYWN0ZXIobWQkQkFMLkRhdGUpCiMgZGF0YSA9IGRhdGEgJT4lIAojICAgbGVmdF9qb2luKC4sIG1kLCBieSA9IGMoInNhbXBsZV9pZCIgPSAiU2FtcGxlLi4iLCAiSUQiID0gIlN0dWR5LklEIikpICU+JSAKIyAgIGxlZnRfam9pbiguLCBzaW1wbGVfbWQsIGJ5ID0gYygiSUQiID0gIlN0dWR5LklEIikpICU+JSAKIyAgIGxlZnRfam9pbiguLCBlZHdfZW5kcG9pbnRzLCBieSA9IGMoIklEIiA9ICJwdF9zdHVkeV9pZCIpKSAlPiUgCiMgICBsZWZ0X2pvaW4oLiwgZWR3X21pY3JvLCBieSA9IGMoIklEIiA9ICJwdC5zdHVkeS5pZCIsICJCQUwuRGF0ZSIgPSAib3JkZXIuZGF0ZXRpbWUiKSkKIyBvbmx5X21ldGFkYXRhID0gbWQgJT4lIAojICAgbGVmdF9qb2luKC4sIHNpbXBsZV9tZCwgYnkgPSAiU3R1ZHkuSUQiKSAlPiUgCiMgICBsZWZ0X2pvaW4oLiwgZWR3X2VuZHBvaW50cywgYnkgPSBjKCJTdHVkeS5JRCIgPSAicHRfc3R1ZHlfaWQiKSkgJT4lIAojICAgbGVmdF9qb2luKC4sIGVkd19taWNybywgYnkgPSBjKCJTdHVkeS5JRCIgPSAicHQuc3R1ZHkuaWQiLCAiQkFMLkRhdGUiID0gIm9yZGVyLmRhdGV0aW1lIikpCiMgb25seV9tZXRhZGF0YSA9IHVuaXF1ZShvbmx5X21ldGFkYXRhKQojIGRhdGEkQkFMLkRhdGUgPSBhcy5EYXRlKGRhdGEkQkFMLkRhdGUpCiMgZWR3X21pY3JvJG9yZGVyLmRhdGV0aW1lID0gYXMuRGF0ZShlZHdfbWljcm8kb3JkZXIuZGF0ZXRpbWUpCgojYWRkIEVEVyBtb2xlY3VsYXIgZGF0YSAgIAplZHdfbW9sZWN1bGFyID0gcmVhZC5jc3YoIn4vQm94L1JHcmFudC9TQ1JJUFQvMjAwNjA4IFNDUklQVCBhbmQgQ09WSUQgQkFMIFJlc3VsdHMuY3N2IiwKICAgICAgICAgICAgICAgICAgICAgICAgIG5hLnN0cmluZ3MgPSBjKCIiLCAiTkEiKSwKICAgICAgICAgICAgICAgICAgICAgICAgIHN0cmlwLndoaXRlID0gVCwKICAgICAgICAgICAgICAgICAgICAgICAgIGNoZWNrLm5hbWVzID0gVCkgJT4lIAogIHNlbGVjdCgtTmFtZSkKI21ha2UgbnVtZXJpYyB2YWx1ZXMgbnVtZXJpYyAgIApudW1lcmljX2NvbHMgPSBjKCJkYXlfb2ZfaW50dWJhdGlvbiIsICJkYXlfb2ZfaG9zcGl0YWxpemF0aW9uIiwgIlJCQ19CT0RZX0ZMVUlEIiwgIldCQ19fQk9EWV9GTFVJRCIsICJORVVUUk9QSElMU19fQk9EWV9GTFVJRCIsCiAgICAgICAgICAgICAgICAgIkFic29sdXRlX05ldXRyb3BoaWxzIiwgIlRPWElDX0dSQU5VTEFUSU9OIiwgIk1BQ1JPUEhBR0VfQkYiLCAiTU9OT0NZVEVfQkYiLCAiTFlNUEhfQkYiLCAKICAgICAgICAgICAgICAgICAiQUJTT0xVVEVfTFlNUEhPQ1lURVMiLCAiRU9TSU5PUEhJTFNfX0JPRFlfRkxVSUQiLCAiQUJTT0xVVEVfRU9TSU5PUEhJTFMiLCAiUExBU01BX0NFTExfQkYiLAogICAgICAgICAgICAgICAgICJPVEhFUl9DRUxMU19fQk9EWV9GTFVJRCIsICJBTVlMQVNFX0JGIiwgIldISVRFX0JMT09EX0NFTExfQ09VTlQiLCAKICAgICAgICAgICAgICAgICAiQ19SZWFjdGl2ZV9Qcm90ZWluIiwgIkxESCIsICJDUkVBVElORV9LSU5BU0VfX1RPVEFMIiwgIlBST0NBTENJVE9OSU4iLCAiRkVSUklUSU4iLCAiVFJPUE9OSU5fSSIsCiAgICAgICAgICAgICAgICAgIkNyZWF0aW5pbmUiLCAiQVNUX19TR09UXyIsICJEX0RJTUVSIiwgIm1heF9kYWlseV90ZW1wIikKZWR3X21vbGVjdWxhciA9IGVkd19tb2xlY3VsYXIgJT4lIG11dGF0ZV9hdCgudmFycyA9IG51bWVyaWNfY29scywgLmZ1bnMgPSBmdW5jdGlvbih4KXsKICB4ID0gZ3N1YigiPiIsICIiLCB4KQogIHggPSBnc3ViKCI8IiwgIiIsIHgpCiAgeCA9IGdzdWIoIiwiLCAiIiwgeCkKICB4ID0gYXMubnVtZXJpYyh4KQogIHJldHVybih4KX0pCiNmaXggdGVzdCBjb2x1bW5zCnRlc3RfY29scyA9IGNvbG5hbWVzKGVkd19tb2xlY3VsYXIpW2Mod2hpY2goY29sbmFtZXMoZWR3X21vbGVjdWxhcikgPT0gIkFTUEVSR0lMTFVTX0dBTEFDVE9NQU5OQU5fQU5USUdFTl9OTUhfTEZIXyIpOndoaWNoKGNvbG5hbWVzKGVkd19tb2xlY3VsYXIpID09ICJSRVNQSVJBVE9SWV9TWU5DWVRJQUxfVklSVVNfUkVTUEFOMjIiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3aGljaChjb2xuYW1lcyhlZHdfbW9sZWN1bGFyKSA9PSAiU1RSRVBUT0NPQ0NVU19QTkVVTU9OSUFFX0FOVElHRU5fVVJJTkVfMSIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdoaWNoKGNvbG5hbWVzKGVkd19tb2xlY3VsYXIpID09ICJMRUdJT05FTExBX0FOVElHRU5fX0VJQV9fVVJJTkVfMSIpKV0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKZWR3X21vbGVjdWxhciA9IGVkd19tb2xlY3VsYXIgJT4lIG11dGF0ZV9hdCgudmFycyA9IHRlc3RfY29scywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLmZ1bnMgPSBmdW5jdGlvbih4KXsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHggPSBmYWN0b3IoaWZlbHNlKGlzLm5hKHgpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHllcyA9IE5BLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5vID0gaWZlbHNlKChncmVwbCgiTm90IERldGVjdGVkIiwgeCwgaWdub3JlLmNhc2UgPSBUKSB8CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JlcGwoIk5lZ2F0aXZlIiwgeCwgaWdub3JlLmNhc2UgPSBUKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeWVzID0gIk5lZ2F0aXZlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBubyA9ICJQb3NpdGl2ZSIpKSkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuKHgpIH0pCgojcmVtb3ZlIG9uZSBzdHJhbmdlIGR1cGxpY2F0ZSBlbnRyeQplZHdfbW9sZWN1bGFyID0gc3Vic2V0KGVkd19tb2xlY3VsYXIsICEoZHVwbGljYXRlZChwYXN0ZShlZHdfbW9sZWN1bGFyJGlyX2lkLCBlZHdfbW9sZWN1bGFyJEJBTF9vcmRlcl90aW1lc3RhbXApKSkpCiNmb3JtYXQgaW50byBsb25nIGZvcm0KZWR3X21vbGVjdWxhciA9IGVkd19tb2xlY3VsYXIgJT4lIAogIHBpdm90X2xvbmdlcihjb2xzID0gY29udGFpbnMoIm9yZ2FuaXNtXyIpLAogICAgICAgICAgICAgICBuYW1lc190byA9ICJtaWNyb2Jpb2xvZ3lfcGFyYW1ldGVyIiwKICAgICAgICAgICAgICAgdmFsdWVzX3RvID0gIm1pY3JvYmlvbG9neV92YWx1ZSIpIAplZHdfbW9sZWN1bGFyJG1haW5fbWljcm9iaW9sb2d5X3BhcmFtZXRlciA9IGZhY3Rvcihnc3ViKCJfKlxcZCIsICIiLCBlZHdfbW9sZWN1bGFyJG1pY3JvYmlvbG9neV9wYXJhbWV0ZXIpKQojZmxhdHRlbiB0aGVzZSBwYXJhbWV0ZXJzIGludG8gbGlzdHMgb2YgdmFsdWVzCmVkd19tb2xlY3VsYXIgPSBlZHdfbW9sZWN1bGFyICU+JQogIGdyb3VwX2J5KGlyX2lkLCBCQUxfb3JkZXJfdGltZXN0YW1wLCBtYWluX21pY3JvYmlvbG9neV9wYXJhbWV0ZXIpICU+JQogIG11dGF0ZShtaWNyb2Jpb2xvZ3lfdmFsdWVfbGlzdCA9IGxpc3QobWljcm9iaW9sb2d5X3ZhbHVlKSkgJT4lICAjIGxpc3QgY29sdW1uCiAgdW5ncm91cCgpICU+JSAKICByb3d3aXNlKCkgJT4lIAogIG11dGF0ZV9hdCgudmFycyA9ICJtaWNyb2Jpb2xvZ3lfdmFsdWVfbGlzdCIsIC5mdW5zID0gZnVuY3Rpb24oeCl7ICNyZW1vdmUgTkEKICAgY3VyID0gbmEub21pdCh4KQogICBpZihsZW5ndGgoY3VyKSA9PSAwKQogICB7CiAgICAgcmV0dXJuKGxpc3QoTlVMTCkpCiAgIH0gZWxzZQogICB7CiAgICByZXR1cm4obGlzdChjdXIpKQogICB9CiAgfSkgJT4lIAogIHNlbGVjdCgtYyhtaWNyb2Jpb2xvZ3lfcGFyYW1ldGVyLCBtaWNyb2Jpb2xvZ3lfdmFsdWUpKSAlPiUgCiAgdW5ncm91cCgpCiNwaXZvdCBiYWNrIGludG8gd2lkZSBmb3JtIGZvciBtZXJnaW5nIChsaXN0IHZhbHVlcyBnZXQgZHVwbGljYXRlZCwgbmVlZCB0byBmaXgpCmxpc3Rjb2xzID0gYXMuY2hhcmFjdGVyKHVuaXF1ZShlZHdfbW9sZWN1bGFyJG1haW5fbWljcm9iaW9sb2d5X3BhcmFtZXRlcikpCmVkd19tb2xlY3VsYXIgPSBlZHdfbW9sZWN1bGFyICU+JQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBtYWluX21pY3JvYmlvbG9neV9wYXJhbWV0ZXIsCiAgICAgICAgICAgICAgdmFsdWVzX2Zyb20gPSBtaWNyb2Jpb2xvZ3lfdmFsdWVfbGlzdCkgJT4lIAogIHJvd3dpc2UoKSAlPiUgCiAgI2hhdmUgdG8gcmVtb3ZlIGR1cGxpY2F0ZWQgbGlzdCB2YWxzCiAgbXV0YXRlX2F0KC52YXJzID0gbGlzdGNvbHMsIC5mdW5zID0gZnVuY3Rpb24oeCl7IAogICAgICAgICAgICAgIHJldHVybihsaXN0KHhbWzFdXSkpIH0pICU+JSAKICB1bmdyb3VwKCkKZWR3X21vbGVjdWxhciRvcmRlcl9hY2Nlc3Npb25fbnVtID0gYXMuY2hhcmFjdGVyKGVkd19tb2xlY3VsYXIkb3JkZXJfYWNjZXNzaW9uX251bSkKI2ZpeCBkYXRlcwpkYXRlX2NvbHMgPSBjb2xuYW1lcyhlZHdfbW9sZWN1bGFyKVtncmVwbCgiZGF0ZSIsIGNvbG5hbWVzKGVkd19tb2xlY3VsYXIpLCBpZ25vcmUuY2FzZSA9IFQpXQplZHdfbW9sZWN1bGFyID0gZWR3X21vbGVjdWxhciAlPiUgCiAgbXV0YXRlX2F0KC52YXJzID0gZGF0ZV9jb2xzLCAuZnVucyA9IGZ1bmN0aW9uKHgpewogICAgYXMuRGF0ZSh4LCBmb3JtYXQgPSAiJW0vJWQvJXkiLCB0eiA9ICJDU1QiKX0gKQojbWFrZSBvcmdhbmlzbSBxdWFudGl0eSBudW1lcmljCmVkd19tb2xlY3VsYXIkb3JnYW5pc21fcXVhbnRpdHkgPSBsYXBwbHkoZWR3X21vbGVjdWxhciRvcmdhbmlzbV9xdWFudGl0eSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmdW5jdGlvbih4KXsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHggPSBnc3ViKCI+IiwgIiIsIHgpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4ID0gZ3N1YigiPCIsICIiLCB4KQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeCA9IGdzdWIoIiwiLCAiIiwgeCkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHggPSBhcy5udW1lcmljKHgpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZihsZW5ndGgoeCkgPT0gMCkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuKE5VTEwpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4oeCl9KQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCgojaW1wb3J0IEJBTCBkYXRhICAgCmVkd19CQUwgPSByZWFkLmNzdigifi9Cb3gvUkdyYW50L1NDUklQVC8yMDA2MDggU0NSSVBUIEJBTCBSZWxhdGVkIExhYnMuY3N2IiwKICAgICAgICAgICAgICAgICAgIG5hLnN0cmluZ3MgPSBjKCIiLCAiTkEiKSwKICAgICAgICAgICAgICAgICAgICAgICAgIHN0cmlwLndoaXRlID0gVCwKICAgICAgICAgICAgICAgICAgICAgICAgIGNoZWNrLm5hbWVzID0gVCkgJT4lIAogIHNlbGVjdChjKGlyX2lkLCBwdF9zdHVkeV9pZCwgcmVkY2FwX2JhbF9kdCkpICU+JSAjdGhlc2UgY29sdW1ucyBhcmVuJ3QgaGVscGZ1bAogIHVuaXF1ZSgpCmVkd19CQUwkcHRfc3R1ZHlfaWQgPSBhcy5jaGFyYWN0ZXIoZWR3X0JBTCRwdF9zdHVkeV9pZCkKZWR3X0JBTCRyZWRjYXBfYmFsX2R0ID0gYXMuRGF0ZShlZHdfQkFMJHJlZGNhcF9iYWxfZHQpCmNvbG5hbWVzKGVkd19CQUwpW2NvbG5hbWVzKGVkd19CQUwpID09ICJiYWxfb3JkZXJfZGF0ZSJdID0gIkJBTF9vcmRlcl9kYXRlIgoKI2ltcG9ydCBrbm93biBDT1ZJRCBwYXRpZW50cyBhbmQgYWxsIHBhdGllbnQgSURzCmNvdmlkX2Nhc2VzID0gcmVhZC5jc3YoIn4vQm94L1JHcmFudC9TQ1JJUFQvMjAwNjA4IFNDUklQVF9DT1ZJRF9saXN0LmNzdiIsCiAgICAgICAgICAgICAgICAgICAgICAgIG5hLnN0cmluZ3MgPSBjKCIiLCAiTkEiKSwKICAgICAgICAgICAgICAgICAgICAgICAgIHN0cmlwLndoaXRlID0gVCwKICAgICAgICAgICAgICAgICAgICAgICAgIGNoZWNrLm5hbWVzID0gVCwKICAgICAgICAgICAgICAgICAgICAgICBjb2xDbGFzc2VzID0gcmVwKCJjaGFyYWN0ZXIiLCA1KSkKY292aWRfY2FzZXMkY292aWRfY29uZmlybWVkID0gVAphbGxfcGF0aWVudHMgPSByZWFkLmNzdigifi9Cb3gvUkdyYW50L1NDUklQVC9TVFUwMDIwNDg2OF9zdWJqZWN0c18wNl8wNF8yMDIwLmNzdiIsCiAgICAgICAgICAgICAgICAgICAgICAgIG5hLnN0cmluZ3MgPSBjKCIiLCAiTkEiKSwKICAgICAgICAgICAgICAgICAgICAgICAgIHN0cmlwLndoaXRlID0gVCwKICAgICAgICAgICAgICAgICAgICAgICAgIGNoZWNrLm5hbWVzID0gVCwgCiAgICAgICAgICAgICAgICAgICAgICAgIGNvbENsYXNzZXMgPSByZXAoImNoYXJhY3RlciIsIDEwKSkgJT4lIAogIHNlcGFyYXRlX3Jvd3MoY2FzZS5udW1iZXIsIHNlcCA9ICIsICIpICN1bmNvbGxhcHNlIElEIGNvbHVtbgpwYXRpZW50X2RhdGEgPSBmdWxsX2pvaW4oY292aWRfY2FzZXMsCiAgICAgICAgICAgICAgICAgICAgICAgICBhbGxfcGF0aWVudHMsCiAgICAgICAgICAgICAgICAgICAgICAgICBieSA9IGMoImNsYXJpdHlfd2VzdF9tcm4iID0gIm5taGNfcmVjb3JkX251bWJlciIpKSAlPiUgCiAgc2VsZWN0KC1jKGZpcnN0X25hbWUsIGxhc3RfbmFtZSwgYWRkcmVzcy5saW5lLjE6ZW1haWwsIG5tZmZfcmVjb3JkX251bWJlciwgbm1oX3JlY29yZF9udW1iZXIsCiAgICAgICAgICAgIGZpcnN0Lm5hbWUsIGxhc3QubmFtZSkpICNzb21lIGFyZSBkdXBsaWNhdGVkCmNvbG5hbWVzKHBhdGllbnRfZGF0YSlbY29sbmFtZXMocGF0aWVudF9kYXRhKSA9PSAiY2FzZS5udW1iZXIiXSA9ICJzdHVkeV9pZCIKCiNtZXJnZSBtZXRhZGF0YQplZHdfbW9sZWN1bGFyJGlyX2lkID0gYXMuY2hhcmFjdGVyKGVkd19tb2xlY3VsYXIkaXJfaWQpCmVkd19lbmRwb2ludHMkaXJfaWQgPSBhcy5jaGFyYWN0ZXIoZWR3X2VuZHBvaW50cyRpcl9pZCkKb25seV9tZXRhZGF0YSA9IGxlZnRfam9pbihlZHdfbW9sZWN1bGFyLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBwYXRpZW50X2RhdGEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgYnkgPSBjKCJpcl9pZCIpKSAlPiUKICBzZWxlY3QoLU1STikgJT4lIAogIGZ1bGxfam9pbiguLAogICAgICAgICAgICAgICBlZHdfZW5kcG9pbnRzLAogICAgICAgICAgICAgICBieSA9IGMoImlyX2lkIiwgInN0dWR5X2lkIiA9ICJwdF9zdHVkeV9pZCIpKSAlPiUgCiAgc2VsZWN0KC13ZXN0X21ybikKCiNmaXggY29sbmFtZXMKY29sbmFtZXMoZGF0YSkgPSBnc3ViKCJcXC4iLCAiXyIsIGNvbG5hbWVzKGRhdGEpKSAjSSBsaWtlIHVuZGVyc2NvcmVzCmNvbG5hbWVzKGRhdGEpID0gZ3N1YigiXyskIiwgIiIsIGNvbG5hbWVzKGRhdGEpKSAjIHJlbW92ZSB0cmFpbGluZwpjb2xuYW1lcyhkYXRhKSA9IGdzdWIoIl8rIiwgIl8iLCBjb2xuYW1lcyhkYXRhKSkgI3JlbW92ZSBkdXAgdW5kZXJzY29yZXMKY29sbmFtZXMob25seV9tZXRhZGF0YSkgPSBnc3ViKCJcXC4iLCAiXyIsIGNvbG5hbWVzKG9ubHlfbWV0YWRhdGEpKSAKY29sbmFtZXMob25seV9tZXRhZGF0YSkgPSBnc3ViKCJfKyQiLCAiIiwgY29sbmFtZXMob25seV9tZXRhZGF0YSkpIApjb2xuYW1lcyhvbmx5X21ldGFkYXRhKSA9IGdzdWIoIl8rIiwgIl8iLCBjb2xuYW1lcyhvbmx5X21ldGFkYXRhKSkKCiNkZXJpdmUgYWRkaXRpb25hbCBtZXRhZGF0YQpvbmx5X21ldGFkYXRhJGRheXNfZnJvbV9kZWF0aCA9IGFzLm51bWVyaWMoZGlmZnRpbWUob25seV9tZXRhZGF0YSRCQUxfb3JkZXJfZGF0ZSwgb25seV9tZXRhZGF0YSRkZWF0aF9kYXRlLCB1bml0cyA9ICJkYXlzIikpCm9ubHlfbWV0YWRhdGEkY292aWRfY29uZmlybWVkW2lzLm5hKG9ubHlfbWV0YWRhdGEkY292aWRfY29uZmlybWVkKV0gPSBGQUxTRSAjbWF5IGJlIGEgc2FmZXIgd2F5IHRvIGRvIHRoaXMKb25seV9tZXRhZGF0YSR2ZW50aWxhdG9yX2RheXMgPSBhcy5udW1lcmljKGRpZmZ0aW1lKG9ubHlfbWV0YWRhdGEkQkFMX29yZGVyX2RhdGUsIG9ubHlfbWV0YWRhdGEkZmlyc3RfaW50dWJhdGlvbl9kYXRlLCB1bml0cyA9ICJkYXlzIikpCgojbWVyZ2Ugd2l0aCBmbG93IGRhdGEKZGF0YSRzb3J0X2RhdGUgPSBhcy5EYXRlKHN1YnN0cmluZyhkYXRhJFNhbXBsZSwgMSwgOCksIAogICAgICAgICAgICAgICAgICAgICAgICBmb3JtYXQgPSAiJVklbSVkIikKbWVyZ2VfZGF0ZSA9IHJlcChOQSwgbnJvdyhkYXRhKSkKZm9yKGkgaW4gMTpucm93KGRhdGEpKQp7CiAgI2dldCBwYXRpZW50IGlkIGFuZCBiYWwgb3JkZXIgZGF0ZSBmb3IgZWFjaCBlbnRyeQogIGN1ciA9IGRhdGFbaSwgXQogIHBhdGllbnQgPSBjdXIkSUQKICBzb3J0X2RhdGUgPSBjdXIkc29ydF9kYXRlCiAgbGF0ZXN0ID0gYXMuRGF0ZShzb3J0X2RhdGUpCiAgZWFybGllc3QgPSBhcy5EYXRlKHNvcnRfZGF0ZSAtIDEpICMyNGhyIHdpbmRvdwogIAogICNwZXJmb3JtIG1hdGNoaW5nIChzaG91bGQganVzdCBiZSBvbmUgbWF0Y2ggcGVyKQogIG1hdGNoZXMgPSBzdWJzZXQob25seV9tZXRhZGF0YSwgCiAgICAgICAgICAgICAgICAgICBzdHVkeV9pZCA9PSBwYXRpZW50ICYgQkFMX29yZGVyX2RhdGUgPj0gZWFybGllc3QgJiBCQUxfb3JkZXJfZGF0ZSA8PSBsYXRlc3QpCiAgaWYobnJvdyhtYXRjaGVzKSA9PSAwKQogIHsKICAgIHdhcm5pbmcocGFzdGUoIlVubWF0Y2hlZCBzYW1wbGUgd2FybmluZy4gUGF0aWVudDoiLCBwYXRpZW50LCAiU29ydCBkYXRlOiIsIHNvcnRfZGF0ZSkpCiAgICBuZXh0CiAgfSBlbHNlIGlmKG5yb3cobWF0Y2hlcykgPiAxKQogIHsKICAgIHN0b3AocGFzdGUoIkVycm9yOiBtdXRsaXBsZSBtYXRjaGVzIGZvciBzaW5nbGUgc2FtcGxlLiBQYXRpZW50OiIsIHBhdGllbnQsICJTb3J0IGRhdGU6Iiwgc29ydF9kYXRlKSkKICB9IGVsc2UKICB7CiAgICBtZXJnZV9kYXRlW2ldID0gYXMuY2hhcmFjdGVyKG1hdGNoZXMkQkFMX29yZGVyX2RhdGUpCiAgfQp9CmRhdGEgPSBjYmluZChkYXRhLCBtZXJnZV9kYXRlKQpkYXRhJG1lcmdlX2RhdGUgPSBhcy5EYXRlKGRhdGEkbWVyZ2VfZGF0ZSkKCmRhdGEgPSBsZWZ0X2pvaW4oZGF0YSwKICAgICAgICAgICAgICAgICBvbmx5X21ldGFkYXRhLAogICAgICAgICAgICAgICAgIGJ5ID0gYygiSUQiID0gInN0dWR5X2lkIiwgIm1lcmdlX2RhdGUiID0gIkJBTF9vcmRlcl9kYXRlIikpCgojY2FzdCBpbnRvIGxvbmcgZm9ybQpkYXRhID0gdW5pcXVlKGRhdGEpCm1maV9jb2xzID0gY29sbmFtZXMoZGF0YSlbZ3JlcGwoIk1GSSIsIGNvbG5hbWVzKGRhdGEpLCBpZ25vcmUuY2FzZSA9IFQpXQpwZXJjZW50YWdlX2NvbHMgPSBjb2xuYW1lcyhkYXRhKVtncmVwbCgicGVyY2VudCIsIGNvbG5hbWVzKGRhdGEpLCBpZ25vcmUuY2FzZSA9IFQpXQpkYXRhX2xvbmcgPSBkYXRhICU+JSAKICBwaXZvdF9sb25nZXIoY29scyA9IGMobWZpX2NvbHMsIHBlcmNlbnRhZ2VfY29scyksIAogICAgICAgICAgICAgICAgICAgICAgICAgbmFtZXNfdG8gPSAiZmxvd19wYXJhbWV0ZXIiLAogICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWVzX3RvID0gInZhbHVlIikgJT4lIAogIGFycmFuZ2UoSUQsIHZlbnRpbGF0b3JfZGF5cykgI2ZvciBlYXN5IHZpZXdpbmcgbGF0ZXIKZGF0YV9sb25nJGZsb3dfcGFyYW1ldGVyID0gZmFjdG9yKGRhdGFfbG9uZyRmbG93X3BhcmFtZXRlcikKCiNvdXRwdXQgZm9yIHVzZSB3aXRoIGJ1bGsKb3V0bmFtZSA9IHBhc3RlMCgifi9Cb3gvUkdyYW50L1NDUklQVC8iLAogICAgICAgICAgICAgICAgIFN5cy5EYXRlKCksCiAgICAgICAgICAgICAgICAgIl8iLAogICAgICAgICAgICAgICAgICJTQ1JJUFRfY2xpbmljYWxfbWV0YWRhdGFfcHJvY2Vzc2VkLnJkcyIpCnNhdmVSRFMob2JqZWN0ID0gb25seV9tZXRhZGF0YSwKICAgICAgICAgIGZpbGUgPSBvdXRuYW1lKQpvdXRuYW1lID0gcGFzdGUwKCJ+L0JveC9SR3JhbnQvU0NSSVBULyIsCiAgICAgICAgICAgICAgICAgU3lzLkRhdGUoKSwKICAgICAgICAgICAgICAgICAiXyIsCiAgICAgICAgICAgICAgICAgIlNDUklQVF9mbG93X3BsdXNfY2xpbmljYWxfbWV0YWRhdGFfcHJvY2Vzc2VkLnJkcyIpCnNhdmVSRFMob2JqZWN0ID0gZGF0YSwKICAgICAgICAgIGZpbGUgPSBvdXRuYW1lKQoKZGF0YQpgYGAgICAKICAgCiMgU3VtbWFyeSBzdGF0cyAgIAojIyBNZXRhZGF0YSAgIApgYGB7ciByZXN1bHRzPSdhc2lzJ30Kc3VtbWFyeV9kYXRhID0gb25seV9tZXRhZGF0YSAlPiUgCiAgc2VsZWN0KGlyX2lkOk9USEVSX0NFTExTX0JPRFlfRkxVSUQsCiAgICAgICAgIEFNWUxBU0VfQkYsCiAgICAgICAgIFdISVRFX0JMT09EX0NFTExfQ09VTlQ6RF9ESU1FUiwKICAgICAgICAgbWF4X2RhaWx5X3RlbXAsCiAgICAgICAgIG5taF9tcm46YmlubmVkX291dGNvbWUpCmRmU3VtbWFyeShzdW1tYXJ5X2RhdGEsIHBsYWluLmFzY2lpID0gRkFMU0UsIHN0eWxlID0gImdyaWQiLCAKICAgICAgICAgIGdyYXBoLm1hZ25pZiA9IDAuNzUsIHZhbGlkLmNvbCA9IEZBTFNFLCB0bXAuaW1nLmRpciA9ICIvdG1wIikKYGBgCgojIyBEaXN0cmlidXRpb25zICAgCiMjIyBQZXJjZW50YWdlcyAgIApgYGB7cn0KcGVyY2VudGFnZV9kYXRhID0gc3Vic2V0KGRhdGFfbG9uZywgZ3JlcGwoInBlcmNlbnQiLCBkYXRhX2xvbmckZmxvd19wYXJhbWV0ZXIpKQpzaGFwaXJvLnRlc3QocGVyY2VudGFnZV9kYXRhJHZhbHVlKQpoaXN0KHBlcmNlbnRhZ2VfZGF0YSR2YWx1ZSwgYnJlYWtzID0gNTApCmBgYCAgIAogICAKIyMjIE1GSXMgICAKYGBge3J9Cm1maV9kYXRhID0gc3Vic2V0KGRhdGFfbG9uZywgZ3JlcGwoIk1GSSIsIGRhdGFfbG9uZyRmbG93X3BhcmFtZXRlcikpCnNoYXBpcm8udGVzdChtZmlfZGF0YSR2YWx1ZSkKaGlzdChtZmlfZGF0YSR2YWx1ZSwgYnJlYWtzID0gNTApCmBgYCAgIAogICAKRXh0cmVtZWx5IG5vbi1ub3JtYWwgaW4gYm90aCBjYXNlcy4gQXQgdGhlIHZlcnkgbGVhc3QsIHdlIG5lZWQgbm9ucGFyYW1ldHJpYyB0ZXN0cy4gSW4gcmVhbGl0eSwgd2UgcHJvYmFibHkgbmVlZCBub24tcGFyYW1ldHJpYyB0ZXN0cyBvciBiZXRhIHJlZ3Jlc3Npb24uIEhvd2V2ZXIsIHRoaXMgbWF5IG5vdCBiZSB0cnVlIG9mIGluZGl2aWR1YWwgcGFyYW1ldGVycy4gRmlyc3QgbGV0J3Mgc2VlIGlmIHRyYW5zZm9ybWF0aW9ucyBoZWxwLiAgIAoKIyMgUHJvZ3Jlc3Npb25zICAgCmBgYHtyfQpzZXJpYWxfZGF0YSA9IHN1YnNldChwZXJjZW50YWdlX2RhdGEsIElEICVpbiUgc2VyaWFsX3BhdGllbnRzICYgCiAgICAgICAgICAgICAgICAgICAgICAgIShmbG93X3BhcmFtZXRlciAlaW4lIGMoInBlcmNlbnRfQ0Q0X3RvdGFsIiwgInBlcmNlbnRfQ0QyMDZfdG90YWwiLCAicGVyY2VudF90b3RhbF9DRDIwNl9sb3ciLCAicGVyY2VudF90b3RhbF9DRDIwNl9oaWdoIikpKQpnZ3Bsb3Qoc2VyaWFsX2RhdGEsIGFlcyh4ID0gdmVudGlsYXRvcl9kYXlzLCB5ID0gdmFsdWUsIGZpbGwgPSBmbG93X3BhcmFtZXRlcikpICsKICBnZW9tX2Jhcihwb3NpdGlvbiA9ICJzdGFjayIsIHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgZmFjZXRfZ3JpZChJRCB+IC4pICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKQojIGdncGxvdChzZXJpYWxfZGF0YSwgYWVzKHggPSBkYXlzX2Zyb21fZGVhdGgsIHkgPSB2YWx1ZSwgZmlsbCA9IGZsb3dfcGFyYW1ldGVyKSkgKwojICAgZ2VvbV9iYXIocG9zaXRpb24gPSAic3RhY2siLCBzdGF0ID0gImlkZW50aXR5IikgKwojICAgZmFjZXRfZ3JpZChJRCB+IC4pICsKIyAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpCiMgZ2dwbG90KHNlcmlhbF9kYXRhLCBhZXMoeCA9IGRheXNfZnJvbV9leHR1YmF0aW9uLCB5ID0gdmFsdWUsIGZpbGwgPSBmbG93X3BhcmFtZXRlcikpICsKIyAgIGdlb21fYmFyKHBvc2l0aW9uID0gInN0YWNrIiwgc3RhdCA9ICJpZGVudGl0eSIpICsKIyAgIGZhY2V0X2dyaWQoSUQgfiAuKSArCiMgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKQpgYGAgICAKICAgCkFzIGV4cGVjdGVkLCB0aGVyZSBhcHBlYXIgdG8gYmUgbmV1dHJvcGhpbGljIGFuZCBub24tbmV1dHJvcGhpbGljIHRyYWplY3RvcmllcyBjYXB0dXJlZCBoZXJlLiAgIAoKIyMjIFBsb3QgY29udHJpYnV0aW9ucyAoanVzdCBkYXkgMCBmb3Igbm93KSAgIApgYGB7cn0KZGF5MF9wZXJjZW50YWdlcyA9IHN1YnNldChwZXJjZW50YWdlX2RhdGEsIHZlbnRpbGF0b3JfZGF5cyA9PSAwICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgICEoZmxvd19wYXJhbWV0ZXIgJWluJSBjKCJwZXJjZW50X0NENF90b3RhbCIsICJwZXJjZW50X0NEMjA2X3RvdGFsIiwgInBlcmNlbnRfdG90YWxfQ0QyMDZfbG93IiwgInBlcmNlbnRfdG90YWxfQ0QyMDZfaGlnaCIpKSkKZ2dwbG90KGRheTBfcGVyY2VudGFnZXMsIGFlcyh4ID0gSUQsIHkgPSB2YWx1ZSwgZmlsbCA9IGZsb3dfcGFyYW1ldGVyKSkgKwogIGdlb21fYmFyKHBvc2l0aW9uID0gInN0YWNrIiwgc3RhdCA9ICJpZGVudGl0eSIpICsKICBmYWNldF9ncmlkKC4gfiBjb3ZpZF9jb25maXJtZWQsIHNjYWxlcyA9ICJmcmVlX3giKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkKYGBgCgojIFRyYW5zZm9ybWF0aW9ucyAgIAojIyBQZXJjZW50YWdlcyAgIAojIyMgQXJjc2luZSAgIApgYGB7cn0KaGlzdChhc2luKHNxcnQocGVyY2VudGFnZV9kYXRhJHZhbHVlKSksIGJyZWFrcyA9IDUwKQpzaGFwaXJvLnRlc3QoYXNpbihzcXJ0KHBlcmNlbnRhZ2VfZGF0YSR2YWx1ZSkpKQpgYGAgICAKR2V0dGluZyB0aGVyZSEgICAKICAgCiMjIyBMb2dpdCAgIApgYGB7cn0KaGlzdChjYXI6OmxvZ2l0KHBlcmNlbnRhZ2VfZGF0YSR2YWx1ZSksIGJyZWFrcyA9IDUwKQpzaGFwaXJvLnRlc3QoY2FyOjpsb2dpdChwZXJjZW50YWdlX2RhdGEkdmFsdWUpKQpgYGAgICAKVGhpcyBpcyBnZXR0aW5nIHZlcnkgY2xvc2UuIExldCdzIHNlZSBpZiBpbmRpdmlkdWFsIG9ic2VydmF0aW9ucyBhcmUgbm9ybWFsLiAgIAogICAgICAKIyMgSW5kaXZpZHVhbCBwYXJhbWV0ZXJzICAgCmBgYHtyfQpwZXJjZW50YWdlX2RhdGEkbG9naXQgPSBjYXI6OmxvZ2l0KHBlcmNlbnRhZ2VfZGF0YSR2YWx1ZSkKcGVyY2VudGFnZV9kYXRhICU+JQogIGdyb3VwX2J5KGZsb3dfcGFyYW1ldGVyKSAlPiUgCiAgZHBseXI6OnN1bW1hcml6ZShwdmFsID0gc2hhcGlyby50ZXN0KGxvZ2l0KSRwLnZhbHVlKSAgIAoKZ2dwbG90KHBlcmNlbnRhZ2VfZGF0YSwgYWVzKHggPSBsb2dpdCkpICsKICBnZW9tX2hpc3RvZ3JhbSgpICsKICBmYWNldF93cmFwKH4gZmxvd19wYXJhbWV0ZXIpCmBgYCAgIApXZSBjYW4gcHJvYmFibHkgd29yayB3aXRoIHRoaXMsIGFjdHVhbGx5LiBJZGVhbGx5IHdlIHNob3VsZCB0YWxrIHRvIGEgc3RhdGlzdGljaWFuIGF0IHNvbWUgcG9pbnQgYmVmb3JlIHB1YmxpY2F0aW9uLiBVc2Ugbm9ybWFsaXplZCB2YWx1ZXMgZm9yIGFsbCBzdGF0cy4gICAKICAgCiMjIE1GSXMgICAKIyMjIExvZyB0cmFuc2Zvcm0gICAKYGBge3J9Cmhpc3QobG9nMTAobWZpX2RhdGEkdmFsdWUpLCBicmVha3MgPSA1MCkKc2hhcGlyby50ZXN0KGxvZzEwKG1maV9kYXRhJHZhbHVlKSkKYGBgICAgClRyaW1vZGFsPyBCdXQgd2l0aGluIGluZGl2aWR1YWwgcGFyYW1ldGVycyB0aGlzIHNob3VsZCBiZSBva2F5LiAgICAgLiAgIAogICAgICAKIyMgSW5kaXZpZHVhbCBwYXJhbWV0ZXJzICAgCmBgYHtyfQptZmlfZGF0YSRsb2cxMCA9IGxvZzEwKG1maV9kYXRhJHZhbHVlKQptZmlfZGF0YSAlPiUKICBncm91cF9ieShmbG93X3BhcmFtZXRlcikgJT4lIAogIGRwbHlyOjpzdW1tYXJpemUocHZhbCA9IHNoYXBpcm8udGVzdChsb2cxMCkkcC52YWx1ZSkgICAKCmdncGxvdChtZmlfZGF0YSwgYWVzKHggPSBsb2cxMCkpICsKICBnZW9tX2hpc3RvZ3JhbSgpICsKICBmYWNldF93cmFwKH4gZmxvd19wYXJhbWV0ZXIpCmBgYCAgIApMb29rcyBwcmV0dHkgZ29vZC4gICAKICAgICAgCiMgQW5hbHlzaXMgICAKIyMgTUFOQ09WQSAocGVyY2VudGFnZXMpCmBgYHtyIGV2YWw9RkFMU0V9CmRhdGFfd2lkZV9wZXJjZW50YWdlID0gcGVyY2VudGFnZV9kYXRhICU+JSAKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gZmxvd19wYXJhbWV0ZXIsIAogICAgICAgICAgICAgIHZhbHVlc19mcm9tID0gYyhsb2dpdCwgdmFsdWUpKQpkYXRhX3dpZGVfcGVyY2VudGFnZSRjb3ZpZF9jb25maXJtZWRbaXMubmEoZGF0YV93aWRlX3BlcmNlbnRhZ2UkY292aWRfY29uZmlybWVkKV0gPSBGQUxTRQpkYXRhX3dpZGVfcGVyY2VudGFnZSRjb3ZpZF9jb25maXJtZWQgPSBmYWN0b3IoZGF0YV93aWRlX3BlcmNlbnRhZ2UkY292aWRfY29uZmlybWVkKQpkYXRhX3dpZGVfcGVyY2VudGFnZSRyZXNwb25zZSA9IGRhdGFfd2lkZV9wZXJjZW50YWdlICU+JSAKICBzZWxlY3QobG9naXRfcGVyY2VudF9DRDRfdG90YWw6bG9naXRfcGVyY2VudF9vdGhlcnMpCm1hbmNvdmFfZGF0YSA9IGRhdGFfd2lkZV9wZXJjZW50YWdlICU+JSAKICBzZWxlY3QoYyhsb2dpdF9wZXJjZW50X0NENF90b3RhbDpsb2dpdF9wZXJjZW50X290aGVycywgCiAgICAgICAgICAgY292aWRfY29uZmlybWVkLCB2ZW50aWxhdG9yX2RheXMpKSAlPiUgCiAgbmEub21pdCgpCm1hbmNvdmFfZml0ID0gbWFub3ZhKGNiaW5kKGxvZ2l0X3BlcmNlbnRfQ0Q0X3RvdGFsLCBsb2dpdF9wZXJjZW50X0NENF9UcmVncywgbG9naXRfcGVyY2VudF9DRDRfbm9uX1RyZWdzLAogICAgICAgICAgICAgICAgICAgICAgICAgICBsb2dpdF9wZXJjZW50X0NEOF90b3RhbCwgbG9naXRfcGVyY2VudF9DRDIwNl90b3RhbCwgCWxvZ2l0X3BlcmNlbnRfbWFjc19DRDIwNl9oaWdoLAogICAgICAgICAgICAgICAgICAgICAgICAgICBsb2dpdF9wZXJjZW50X3RvdGFsX0NEMjA2X2hpZ2gsIAlsb2dpdF9wZXJjZW50X21hY3NfQ0QyMDZfbG93LCBsb2dpdF9wZXJjZW50X3RvdGFsX0NEMjA2X2xvdywKICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9naXRfcGVyY2VudF9uZXV0cm9waGlscywgbG9naXRfcGVyY2VudF9tb25vY3l0ZXMsIGxvZ2l0X3BlcmNlbnRfb3RoZXJzKSAKICAgICAgICAgICAgICAgICAgICAgfiBjb3ZpZF9jb25maXJtZWQgKiBPdXRjb21lcywKICAgICAgICAgICAgICAgICAgICAgbmEuYWN0aW9uID0gIm5hLm9taXQiLAogICAgICAgICAgICAgICAgICAgICBkYXRhID0gbWFuY292YV9kYXRhKSAjYWRkIG91dGNvbWVzPz8Kc3VtbWFyeS5hb3YobWFuY292YV9maXQpCmBgYCAgIAogICAKVGhlc2UgYXJlIGludGVyZXN0aW5nIHJlc3VsdHMhIFdpdGggdGhlIGV4Y2VwdGlvbiBvZiBtb25vY3l0ZXMsIGFidW5kYW5jZSBvZiBhbGwgY2VsbHMgaXMgYWZmZWN0ZWQgYnkgQ09WSUQtMTkgaW4gc29tZSB3YXkuIEZvciBDRDRULCBhbmQgQ0Q4VCwgdGhpcyBhcHBlYXJzIHRvIGJlIHB1cmVseSBhIG1haW4gZWZmZWN0LiBGb3IgVHJlZ3MgYW5kIHB1dGF0aXZlIE1vQU0sIHRoZXJlIGlzIGFsc28gYW4gaW50ZXJhY3Rpb24gZWZmZWN0IG9mIGRheSBhbmQgaW5mZWN0aW9uLiBGb3IgVFJBTSwgdGhlcmUgaXMgb25seSBhbiBpbnRlcmFjdGlvbiBlZmZlY3QuICAgCiAgIAojIyBWaXN1YWxpemUgICAKQXJlYSBwbG90ICAgCmBgYHtyfQphcmVhX2RhdGEgPSBwZXJjZW50YWdlX2RhdGEgJT4lIAogIGdyb3VwX2J5KGNvdmlkX2NvbmZpcm1lZCwgRGF5LCBmbG93X3BhcmFtZXRlcikgJT4lIAogIGRwbHlyOjpzdW1tYXJpemUobWVhbl9wY3QgPSBtZWFuKHZhbHVlKSkKYXJlYV9kYXRhID0gc3Vic2V0KGFyZWFfZGF0YSwgIShmbG93X3BhcmFtZXRlciAlaW4lIGMoInBlcmNlbnRfQ0Q0X3RvdGFsIiwgInBlcmNlbnRfQ0QyMDZfdG90YWwiLCAicGVyY2VudF90b3RhbF9DRDIwNl9sb3ciLCAicGVyY2VudF90b3RhbF9DRDIwNl9oaWdoIikpKQpnZ3Bsb3QoYXJlYV9kYXRhLCBhZXMoeCA9IERheSwgeSA9IG1lYW5fcGN0LCBmaWxsID0gZmxvd19wYXJhbWV0ZXIpKSArCiAgZ2VvbV9hcmVhKGFscGhhID0gMC43KSArCiAgZmFjZXRfZ3JpZChjb3ZpZF9jb25maXJtZWQgfiAuKQpgYGAKVGhpcyBnaXZlIGEgZmFsc2UgaW1wcmVzc2lvbiBiZXR3ZWVuIHNhbXBsZXMuIEEgbGluZSBwbG90IG1heSBhY3R1YWxseSBiZSBiZXR0ZXIuICAgCiAgIAojIyMgTGluZSBwbG90ICAgCkdyb3VwZWQgICAKYGBge3J9CmdncGxvdChwZXJjZW50YWdlX2RhdGEsIGFlcyh4ID0gdmVudGlsYXRvcl9kYXlzLCB5ID0gdmFsdWUsIGNvbG9yID0gZmxvd19wYXJhbWV0ZXIpKSArCiAgc3RhdF9zdW1tYXJ5KGZ1biA9IG1lYW4sIGdlb20gPSAibGluZSIpICsKICBzdGF0X3N1bW1hcnkoZnVuLmRhdGEgPSBtZWFuX3NlLCBnZW9tID0gImVycm9yYmFyIiwgd2lkdGggPSAwLjUsIGFscGhhID0gMC41KSArCiAgZmFjZXRfZ3JpZChPdXRjb21lcyB+IGNvdmlkX2NvbmZpcm1lZCkKYGBgCgpCeSBwYXRpZW50ICAgCmBgYHtyIGV2YWw9RkFMU0V9CmdncGxvdChwZXJjZW50YWdlX2RhdGEsIGFlcyh4ID0gdmVudGlsYXRvcl9kYXlzLCB5ID0gdmFsdWUsIGNvbG9yID0gZmxvd19wYXJhbWV0ZXIpKSArCiAgZ2VvbV9saW5lKCkgKwogIGZhY2V0X3dyYXAofiBJRCkKYGBgCk5vdCBlbm91Z2ggZGF0YSBhdCB0aGlzIHBvaW50IHRvIGdsZWFuIG11Y2ggb2YgYW55dGhpbmcuICAgCiAgIAojIyBIZWF0bWFwcyBvZiBmbG93IHBhcmFtZXRlcnMgICAKIyMjIEQwICAgICAKYGBge3IgZXZhbD1GQUxTRX0KI2Nhc3QgaW50byBtYXRyaXggb2YgcGF0aWVudCB4IGZsb3cgcGFyYW1ldGVyCmFsbF9kYXkwID0gc3Vic2V0KGRhdGEsIHZlbnRpbGF0b3JfZGF5cyA9PSAwKQptYXRyaXhfZGF0YSA9IHJlc2hhcGUyOjpkY2FzdChkYXRhID0gc3Vic2V0KGRhdGFfbG9uZywgdmVudGlsYXRvcl9kYXlzID09IDApLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmb3JtdWxhID0gSUQgfiBmbG93X3BhcmFtZXRlcikgJT4lIAogIGNvbHVtbl90b19yb3duYW1lcyh2YXIgPSAiSUQiKSAjZWFzaWVyIHRoYW4gcmVtb3ZpbmcgY29sdW1ucwphbm5vdGF0aW9uX2RhdGEgPSBhbGxfZGF5MCAlPiUgCiAgc2VsZWN0KGMoSUQsIE91dGNvbWVzLCBjb3ZpZF9jb25maXJtZWQpKSAlPiUgCiAgY29sdW1uX3RvX3Jvd25hbWVzKHZhciA9ICJJRCIpCgpwaGVhdG1hcChtYXQgPSBtYXRyaXhfZGF0YSwgCiAgICAgICAgIGNsdXN0ZXJfcm93cyA9IFQsCiAgICAgICAgIGNsdXN0ZXJfY29scyA9IFQsCiAgICAgICAgIGNsdXN0ZXJpbmdfbWV0aG9kID0gIndhcmQuRDIiLAogICAgICAgICBhbm5vdGF0aW9uX3JvdyA9IGFubm90YXRpb25fZGF0YSwKICAgICAgICAgc2NhbGUgPSAiY29sdW1uIiwKICAgICAgICAgYW5nbGVfY29sID0gNDUsCiAgICAgICAgIGJyZWFrcyA9IHNlcSgtMywgMywgbGVuZ3RoLm91dD0xMDEpLAogICAgICAgICBjb2xvciA9IGNvbG9yUmFtcFBhbGV0dGUocmV2KGJyZXdlci5wYWwobiA9IDcsIG5hbWUgPSAiUmRCdSIpKSkoMTAxKSkKYGBgICAgCiAgIAojIyMgQWxsIGRheXMgICAKYGBge3IgZXZhbD1GQUxTRX0KbWF0cml4X2RhdGEgPSByZXNoYXBlMjo6ZGNhc3QoZGF0YSA9IGRhdGFfbG9uZywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9ybXVsYSA9IHNhbXBsZV9pZCB+IGZsb3dfcGFyYW1ldGVyKSAlPiUgCiAgY29sdW1uX3RvX3Jvd25hbWVzKHZhciA9ICJzYW1wbGVfaWQiKSAgI2Vhc2llciB0aGFuIHJlbW92aW5nIGNvbHVtbnMKYW5ub3RhdGlvbl9kYXRhID0gZGF0YSAlPiUgCiAgc2VsZWN0KGMoc2FtcGxlX2lkLCBvdXRjb21lLCBDT1ZJRF9zdGF0dXMsIElELCB2ZW50aWxhdG9yX2RheXMpKSAlPiUgCiAgY29sdW1uX3RvX3Jvd25hbWVzKHZhciA9ICJzYW1wbGVfaWQiKQoKcGhlYXRtYXAobWF0ID0gbWF0cml4X2RhdGEsIAogICAgICAgICBjbHVzdGVyX3Jvd3MgPSBULAogICAgICAgICBjbHVzdGVyX2NvbHMgPSBULAogICAgICAgICBjbHVzdGVyaW5nX21ldGhvZCA9ICJ3YXJkLkQyIiwKICAgICAgICAgYW5ub3RhdGlvbl9yb3cgPSBhbm5vdGF0aW9uX2RhdGEsCiAgICAgICAgIHNjYWxlID0gImNvbHVtbiIsCiAgICAgICAgIGFuZ2xlX2NvbCA9IDQ1LAogICAgICAgICBzaG93X3Jvd25hbWVzID0gRiwKICAgICAgICAgYnJlYWtzID0gc2VxKC0zLCAzLCBsZW5ndGgub3V0PTEwMSksCiAgICAgICAgIGNvbG9yID0gY29sb3JSYW1wUGFsZXR0ZShyZXYoYnJld2VyLnBhbChuID0gNywgbmFtZSA9ICJSZEJ1IikpKSgxMDEpKQoKcGhlYXRtYXAobWF0ID0gbWF0cml4X2RhdGEsIAogICAgICAgICBjbHVzdGVyX3Jvd3MgPSBGLAogICAgICAgICBjbHVzdGVyX2NvbHMgPSBULAogICAgICAgICBjbHVzdGVyaW5nX21ldGhvZCA9ICJ3YXJkLkQyIiwKICAgICAgICAgYW5ub3RhdGlvbl9yb3cgPSBhbm5vdGF0aW9uX2RhdGEsCiAgICAgICAgIHNjYWxlID0gImNvbHVtbiIsCiAgICAgICAgIGFuZ2xlX2NvbCA9IDQ1LAogICAgICAgICBzaG93X3Jvd25hbWVzID0gRiwKICAgICAgICAgYnJlYWtzID0gc2VxKC0zLCAzLCBsZW5ndGgub3V0PTEwMSksCiAgICAgICAgIGNvbG9yID0gY29sb3JSYW1wUGFsZXR0ZShyZXYoYnJld2VyLnBhbChuID0gNywgbmFtZSA9ICJSZEJ1IikpKSgxMDEpKQpgYGAKICAgCiMgQ28taW5mZWN0aW9uICAgCiMjIFByb3BvcnRpb24gb2YgbWljcm9iZS1pbmZlY3RlZCBpbmRpdmlkdWFscyAgIAojIyMgUGxvdCAgIApgYGB7cn0Kb25seV9tZXRhZGF0YSA9IG9ubHlfbWV0YWRhdGEgJT4lCiAgcm93d2lzZSgpICU+JSAKICBtdXRhdGUoaW5mZWN0aW9uX2RldGVjdGVkID0gIWlzLm51bGwob3JnYW5pc21fbmFtZSkpICU+JSAKICB1bmdyb3VwKCkKb25seV9tZXRhZGF0YSRpbmZlY3Rpb25fZGV0ZWN0ZWRbaXMubmEob25seV9tZXRhZGF0YSRpbmZlY3Rpb25fZGV0ZWN0ZWQpXSA9ICJOb3QgVGVzdGVkIgpvbmx5X21ldGFkYXRhJGluZmVjdGlvbl9kZXRlY3RlZCA9IGZhY3Rvcihvbmx5X21ldGFkYXRhJGluZmVjdGlvbl9kZXRlY3RlZCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJOb3QgVGVzdGVkIiwgIlRSVUUiLCAiRkFMU0UiKSkKZ2dwbG90KHN1YnNldChvbmx5X21ldGFkYXRhLCAhaXMubmEoY292aWRfY29uZmlybWVkKSksIGFlcyh4ID0gY292aWRfY29uZmlybWVkLCBmaWxsID0gaW5mZWN0aW9uX2RldGVjdGVkKSkgKwogIGdlb21fYmFyKHBvc2l0aW9uID0gImZpbGwiKSArCiAgeWxhYigiUHJvcG9ydGlvbiIpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJOb3QgVGVzdGVkIiA9ICJncmF5IiwgIkZBTFNFIiA9ICJjb3JuZmxvd2VyYmx1ZSIsICJUUlVFIiA9ICJmaXJlYnJpY2siKSkKYGBgCiAgIAojIyBMZXZlbHMgb2YgaW5mZWN0aW9uICAgCiMjIyBIaXN0b2dyYW1zIG9mIHNtZWFyIHF1YW50aXRpZXMgICAKYGBge3J9CmNvdmlkX29yZ2FuaXNtX2xldmVscyA9IG9ubHlfbWV0YWRhdGEgJT4lIAogIGRwbHlyOjpmaWx0ZXIoY292aWRfY29uZmlybWVkID09IFQpICU+JSAKICBzZWxlY3Qob3JnYW5pc21fcXVhbnRpdHkpICU+JSAKICB1bmxpc3QoKQpvdGhlcl9vcmdhbmlzbV9sZXZlbHMgPSBvbmx5X21ldGFkYXRhICU+JSAKICBkcGx5cjo6ZmlsdGVyKGNvdmlkX2NvbmZpcm1lZCA9PSBGKSAlPiUgCiAgc2VsZWN0KG9yZ2FuaXNtX3F1YW50aXR5KSAlPiUgCiAgdW5saXN0KCkKZ2dwbG90KE5VTEwpICsKICBnZW9tX2RlbnNpdHkoYWVzKHggPSBjb3ZpZF9vcmdhbmlzbV9sZXZlbHMpLCBmaWxsID0gImZpcmVicmljayIsIGFscGhhID0gMC41KSArCiAgZ2VvbV9kZW5zaXR5KGFlcyh4ID0gb3RoZXJfb3JnYW5pc21fbGV2ZWxzKSwgZmlsbCA9ICJjb3JuZmxvd2VyYmx1ZSIsIGFscGhhID0gMC41KQpgYGAKCiMjIEluZmVjdGlvbiB0eXBlICAgCiMjIyBXb3JkIGNsb3VkICAgCmBgYHtyfQpjb3ZpZF9vcmdhbmlzbXMgPSBhcy5jaGFyYWN0ZXIob25seV9tZXRhZGF0YSAlPiUgCiAgZHBseXI6OmZpbHRlcihjb3ZpZF9jb25maXJtZWQgPT0gVCkgJT4lIAogIHNlbGVjdChvcmdhbmlzbV9uYW1lKSAlPiUgCiAgdW5saXN0KCkgJT4lIAogIG5hLm9taXQoKSkKY292aWRfb3JnYW5pc21zID0gZ3N1YigiW1s6cHVuY3Q6XV0gfCB8IFtbOnB1bmN0Ol1dfFtbOnB1bmN0Ol1dIiwgIl8iLCB0cmltd3MoY292aWRfb3JnYW5pc21zKSkgI3NvIHdlIGNhbiB0cmVhdCBhcyBvbmUgd29yZApjb3ZpZF9vcmdhbmlzbXMgPSBnc3ViKCJfJCIsICIiLCBjb3ZpZF9vcmdhbmlzbXMpCgpvdGhlcl9vcmdhbmlzbXMgPSBhcy5jaGFyYWN0ZXIob25seV9tZXRhZGF0YSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZHBseXI6OmZpbHRlcihjb3ZpZF9jb25maXJtZWQgPT0gRikgJT4lIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWxlY3Qob3JnYW5pc21fbmFtZSkgJT4lIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1bmxpc3QoKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hLm9taXQoKSkKb3RoZXJfb3JnYW5pc21zID0gZ3N1YigiW1s6cHVuY3Q6XV0gfCB8IFtbOnB1bmN0Ol1dfFtbOnB1bmN0Ol1dIiwgIl8iLCB0cmltd3Mob3RoZXJfb3JnYW5pc21zKSkKb3RoZXJfb3JnYW5pc21zID0gZ3N1YigiXyQiLCAiIiwgb3RoZXJfb3JnYW5pc21zKQoKI21ha2UgaW50byBkYXRhIGZyYW1lIHdpdGggbm9ybWFsaXplZCBmcmVxcwpkZjEgPSBkYXRhLmZyYW1lKHdvcmQgPSBuYW1lcyh0ZXJtRnJlcShjb3ZpZF9vcmdhbmlzbXMpKSwKICAgICAgICAgICAgICAgICBmcmVxID0gYXMubnVtZXJpYyh0ZXJtRnJlcShjb3ZpZF9vcmdhbmlzbXMpKSAvIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3VtKGFzLm51bWVyaWModGVybUZyZXEoY292aWRfb3JnYW5pc21zKSkpLAogICAgICAgICAgICAgICAgIGNvdmlkX2NvbmZpcm1lZCA9IFQpCmRmMiA9IGRhdGEuZnJhbWUod29yZCA9IG5hbWVzKHRlcm1GcmVxKG90aGVyX29yZ2FuaXNtcykpLAogICAgICAgICAgICAgICAgIGZyZXEgPSBhcy5udW1lcmljKHRlcm1GcmVxKG90aGVyX29yZ2FuaXNtcykpIC8KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1bShhcy5udW1lcmljKHRlcm1GcmVxKG90aGVyX29yZ2FuaXNtcykpKSwKICAgICAgICAgICAgICAgICBjb3ZpZF9jb25maXJtZWQgPSBGKQoKI2ZpbmFsbHksIHBsb3QKd29yZGNvdWxkX2RmID0gcmJpbmQoZGYxLCBkZjIpCmdncGxvdCh3b3JkY291bGRfZGYsIGFlcyhsYWJlbCA9IHdvcmQsIHNpemUgPSBmcmVxKSkgKwogIGdlb21fdGV4dF93b3JkY2xvdWQoc2hvdy5sZWdlbmQgPSBGKSArCiAgZmFjZXRfd3JhcCh+IGNvdmlkX2NvbmZpcm1lZCkKYGBgCgogICAKIyBGYWN0b3IgYW5hbHlzaXMgICAKIyMgU3Vic2V0IHRvIHVzYWJsZSBmYWN0b3JzICAgCmBgYHtyfQpjbGluaWNhbF9kYXRhID0gb25seV9tZXRhZGF0YSAlPiUgCiAgdW5pcXVlKCkgJT4lICNvZGRseSB0aGVyZSBpcyBkdXBsaWNhdGlvbgogIGRwbHlyOjpmaWx0ZXIoIWlzLm5hKEJBTF9vcmRlcl9kYXRlKSkgJT4lICNyZW1vdmUgc2FtcGxlcyB3aXRob3V0IEJBTCBpbmZvCiAgbXV0YXRlKHNhbXBsZV9pZCA9IHBhc3RlKGlyX2lkLCBCQUxfb3JkZXJfdGltZXN0YW1wLCBzZXAgPSAiXyIpKSAlPiUgCiAgc2VsZWN0KGMoc2FtcGxlX2lkLAogICAgICAgICAgIFJCQ19CT0RZX0ZMVUlEOkFic29sdXRlX05ldXRyb3BoaWxzLAogICAgICAgICAgIE1BQ1JPUEhBR0VfQkY6T1RIRVJfQ0VMTFNfQk9EWV9GTFVJRCwKICAgICAgICAgICBBTVlMQVNFX0JGLAogICAgICAgICAgIFdISVRFX0JMT09EX0NFTExfQ09VTlQ6RF9ESU1FUiwgCiAgICAgICAgICAgbWF4X2RhaWx5X3RlbXApKSAlPiUgCiAgICBjb2x1bW5fdG9fcm93bmFtZXModmFyID0gInNhbXBsZV9pZCIpCmBgYAogICAKIyMgUENBICAgCiMjIyBDYWxjdWxhdGlvbiAgIApgYGB7cn0Kc2FmZV9jb2xzID0gZnVuY3Rpb24oeCkKewogIHJldHVybihhbGwoaXMuZmluaXRlKG5hLm9taXQoeCkpKSAmIAogICAgICAgICAgIHNkKHgsIG5hLnJtID0gVCkgPiAwICYKICAgICAgICAgICBzdW0oIWlzLm5hKHgpKSA+IChsZW5ndGgoeCkgLyAyKSkKfQprZWVwX2NvbHMgPSBhcHBseShjbGluaWNhbF9kYXRhLCAyLCBzYWZlX2NvbHMpCnBjYV9kYXRhID0gbmEub21pdChjbGluaWNhbF9kYXRhWywga2VlcF9jb2xzXSkKCiNuZWVkIHRvIHVzZSBmb3JtdWxhIGludGVyZmFjZSB0byBkZWFsIHdpdGggTkFzIGJlY2F1c2Ugbm90aGluZyBpcyBldmVyIGVhc3kKZm9ybXVsYSA9IHBhc3RlMCgifiAiLAogICAgICAgICAgICAgICAgIHBhc3RlKGNvbG5hbWVzKHBjYV9kYXRhKSwgY29sbGFwc2UgPSAiKyIpKQpmb3JtdWxhID0gYXMuZm9ybXVsYShmb3JtdWxhKQpwY2EgPSBwcmNvbXAoZm9ybXVsYSA9IGZvcm11bGEsCiAgICAgICAgICAgICBkYXRhID0gcGNhX2RhdGEsIAogICAgICAgICAgICAgc2NhbGUuID0gVCwKICAgICAgICAgICAgIG5hLmFjdGlvbiA9IG5hLm9taXQpCgpwY2FfZGF0YV9jb21wbGV0ZSA9IG9ubHlfbWV0YWRhdGEgJT4lIAogIHVuaXF1ZSgpICU+JQogIG11dGF0ZShzYW1wbGVfaWQgPSBwYXN0ZShpcl9pZCwgQkFMX29yZGVyX3RpbWVzdGFtcCwgc2VwID0gIl8iKSkgJT4lIAogIGRwbHlyOjpmaWx0ZXIoc2FtcGxlX2lkICVpbiUgcm93bmFtZXMocGNhX2RhdGEpKSAlPiUgCiAgY29sdW1uX3RvX3Jvd25hbWVzKHZhciA9ICJzYW1wbGVfaWQiKQpgYGAgICAKICAgCiMjIyBTY3JlZXBsb3QgICAKYGBge3J9CmZ2aXpfZWlnKHBjYSkKYGBgCgogICAKIyMjIEJpcGxvdCAgIApgYGB7cn0KYXV0b3Bsb3QocGNhLCAKICAgICAgICAgZGF0YSA9IHBjYV9kYXRhX2NvbXBsZXRlLCAKICAgICAgICAgY29sb3VyID0gImJpbm5lZF9vdXRjb21lIiwKICAgICAgICAgc2hhcGUgPSAiY292aWRfY29uZmlybWVkIiwKICAgICAgICAgbG9hZGluZ3MgPSBUUlVFLCAKICAgICAgICAgbG9hZGluZ3MuY29sb3VyID0gYWxwaGEoImJsdWUiLCAwLjEpLAogICAgICAgICBsb2FkaW5ncy5sYWJlbCA9IFRSVUUsIAogICAgICAgICBsb2FkaW5ncy5sYWJlbC5zaXplID0gMiwKICAgICAgICAgbG9hZGluZ3MubGFiZWwuY29sb3VyID0gYWxwaGEoInJlZCIsIDAuNyksCiAgICAgICAgIHggPSAxLAogICAgICAgICB5ID0gMikKYXV0b3Bsb3QocGNhLCAKICAgICAgICAgZGF0YSA9IHBjYV9kYXRhX2NvbXBsZXRlLCAKICAgICAgICAgY29sb3VyID0gImJpbm5lZF9vdXRjb21lIiwKICAgICAgICAgc2hhcGUgPSAiY292aWRfY29uZmlybWVkIiwKICAgICAgICAgbG9hZGluZ3MgPSBUUlVFLCAKICAgICAgICAgbG9hZGluZ3MuY29sb3VyID0gYWxwaGEoImJsdWUiLCAwLjEpLAogICAgICAgICBsb2FkaW5ncy5sYWJlbCA9IFRSVUUsIAogICAgICAgICBsb2FkaW5ncy5sYWJlbC5zaXplID0gMiwKICAgICAgICAgbG9hZGluZ3MubGFiZWwuY29sb3VyID0gYWxwaGEoInJlZCIsIDAuNyksCiAgICAgICAgIHggPSAyLAogICAgICAgICB5ID0gMykKYXV0b3Bsb3QocGNhLCAKICAgICAgICAgZGF0YSA9IHBjYV9kYXRhX2NvbXBsZXRlLCAKICAgICAgICAgY29sb3VyID0gImJpbm5lZF9vdXRjb21lIiwKICAgICAgICAgc2hhcGUgPSAiY292aWRfY29uZmlybWVkIiwKICAgICAgICAgbG9hZGluZ3MgPSBUUlVFLCAKICAgICAgICAgbG9hZGluZ3MuY29sb3VyID0gYWxwaGEoImJsdWUiLCAwLjEpLAogICAgICAgICBsb2FkaW5ncy5sYWJlbCA9IFRSVUUsIAogICAgICAgICBsb2FkaW5ncy5sYWJlbC5zaXplID0gMiwKICAgICAgICAgbG9hZGluZ3MubGFiZWwuY29sb3VyID0gYWxwaGEoInJlZCIsIDAuNyksCiAgICAgICAgIHggPSAzLAogICAgICAgICB5ID0gNCkKYGBgICAgClNvbWUgaW50ZXJlc3RpbmcgbG9hZGluZ3M6IFBDMS0yIGlzIGRyaXZlbiBoZWF2aWx5IGJ5IG1hcmtlcnMgb2Ygc2Vwc2lzIGFuZC9vciBvcmdhbiBmYWlsdXJlLiBQQzMgYXBwZWFycyB0byBqdXN0IGJyb2FkbHkgYmUgaW1tdW5lIHJlc3BvbnNlLCBidXQgSSBmaW5kIGl0IGludGVyZXN0aW5nIHRoYXQgQ1JQIGFuZCBtb25vY3l0ZXMgKGluIHRoaXMgY2FzZSBmcm9tIEJBTCkgdHJhdmVsIHRvZ2V0aGVyLiBBcmUgdGhleSB0aGUgc291cmNlIG9mIElMNj8gSXMgdGhpcyBhIHJlc3BvbnNlIHRvIElMNj8gUEM0IGlzIHNpbWlsYXIsIHdpdGggaW5mbHVlbmNlIG9mIENSUCBhbmQgZmVycml0aW4gc3VnZ2VzdGluZyBoaWdoIGxldmVscyBvZiBpbmZsYW1tYXRpb24uIExldCdzIGFsc28gdHJ5IFVNQVAgdG8gc2VlIGlmIHRoZXJlIGlzIHNvbWUgaGlkZGVuIHN0cnVjdHVyZS4gICAKICAKIyMjIENhbGN1bGF0aW9uIG9uIGZld2VyIHBhcmFtZXRlcnMgICAKYGBge3J9CmNsaW5pY2FsX2RhdGFfbHRkID0gb25seV9tZXRhZGF0YSAlPiUgCiAgdW5pcXVlKCkgJT4lICNvZGRseSB0aGVyZSBpcyBkdXBsaWNhdGlvbgogIGRwbHlyOjpmaWx0ZXIoIWlzLm5hKEJBTF9vcmRlcl9kYXRlKSkgJT4lICNyZW1vdmUgc2FtcGxlcyB3aXRob3V0IEJBTCBpbmZvCiAgbXV0YXRlKHNhbXBsZV9pZCA9IHBhc3RlKGlyX2lkLCBCQUxfb3JkZXJfdGltZXN0YW1wLCBzZXAgPSAiXyIpKSAlPiUgCiAgc2VsZWN0KGMoc2FtcGxlX2lkLAogICAgICAgICAgIEFic29sdXRlX05ldXRyb3BoaWxzLAogICAgICAgICAgIFdISVRFX0JMT09EX0NFTExfQ09VTlQ6RF9ESU1FUiwgCiAgICAgICAgICAgbWF4X2RhaWx5X3RlbXApKSAlPiUgCiAgICBjb2x1bW5fdG9fcm93bmFtZXModmFyID0gInNhbXBsZV9pZCIpCgprZWVwX2NvbHMgPSBhcHBseShjbGluaWNhbF9kYXRhX2x0ZCwgMiwgc2FmZV9jb2xzKQpwY2FfZGF0YSA9IG5hLm9taXQoY2xpbmljYWxfZGF0YV9sdGRbLCBrZWVwX2NvbHNdKQoKI25lZWQgdG8gdXNlIGZvcm11bGEgaW50ZXJmYWNlIHRvIGRlYWwgd2l0aCBOQXMgYmVjYXVzZSBub3RoaW5nIGlzIGV2ZXIgZWFzeQpmb3JtdWxhID0gcGFzdGUwKCJ+ICIsCiAgICAgICAgICAgICAgICAgcGFzdGUoY29sbmFtZXMocGNhX2RhdGEpLCBjb2xsYXBzZSA9ICIrIikpCmZvcm11bGEgPSBhcy5mb3JtdWxhKGZvcm11bGEpCnBjYSA9IHByY29tcChmb3JtdWxhID0gZm9ybXVsYSwKICAgICAgICAgICAgIGRhdGEgPSBwY2FfZGF0YSwgCiAgICAgICAgICAgICBzY2FsZS4gPSBULAogICAgICAgICAgICAgbmEuYWN0aW9uID0gbmEub21pdCkKCnBjYV9kYXRhX2NvbXBsZXRlID0gb25seV9tZXRhZGF0YSAlPiUgCiAgdW5pcXVlKCkgJT4lCiAgbXV0YXRlKHNhbXBsZV9pZCA9IHBhc3RlKGlyX2lkLCBCQUxfb3JkZXJfdGltZXN0YW1wLCBzZXAgPSAiXyIpKSAlPiUgCiAgZHBseXI6OmZpbHRlcihzYW1wbGVfaWQgJWluJSByb3duYW1lcyhwY2FfZGF0YSkpICU+JSAKICBjb2x1bW5fdG9fcm93bmFtZXModmFyID0gInNhbXBsZV9pZCIpCmBgYAoKIyMjIEJpcGxvdCAgIApgYGB7cn0KYXV0b3Bsb3QocGNhLCAKICAgICAgICAgZGF0YSA9IHBjYV9kYXRhX2NvbXBsZXRlLCAKICAgICAgICAgY29sb3VyID0gImJpbm5lZF9vdXRjb21lIiwKICAgICAgICAgbG9hZGluZ3MgPSBUUlVFLCAKICAgICAgICAgbG9hZGluZ3MuY29sb3VyID0gYWxwaGEoImJsdWUiLCAwLjEpLAogICAgICAgICBsb2FkaW5ncy5sYWJlbCA9IFRSVUUsIAogICAgICAgICBsb2FkaW5ncy5sYWJlbC5zaXplID0gMiwKICAgICAgICAgbG9hZGluZ3MubGFiZWwuY29sb3VyID0gYWxwaGEoInJlZCIsIDAuNyksCiAgICAgICAgIHggPSAxLAogICAgICAgICB5ID0gMikKYXV0b3Bsb3QocGNhLCAKICAgICAgICAgZGF0YSA9IHBjYV9kYXRhX2NvbXBsZXRlLCAKICAgICAgICAgY29sb3VyID0gImJpbm5lZF9vdXRjb21lIiwKICAgICAgICAgbG9hZGluZ3MgPSBUUlVFLCAKICAgICAgICAgbG9hZGluZ3MuY29sb3VyID0gYWxwaGEoImJsdWUiLCAwLjEpLAogICAgICAgICBsb2FkaW5ncy5sYWJlbCA9IFRSVUUsIAogICAgICAgICBsb2FkaW5ncy5sYWJlbC5zaXplID0gMiwKICAgICAgICAgbG9hZGluZ3MubGFiZWwuY29sb3VyID0gYWxwaGEoInJlZCIsIDAuNyksCiAgICAgICAgIHggPSAyLAogICAgICAgICB5ID0gMykKYXV0b3Bsb3QocGNhLCAKICAgICAgICAgZGF0YSA9IHBjYV9kYXRhX2NvbXBsZXRlLCAKICAgICAgICAgY29sb3VyID0gImJpbm5lZF9vdXRjb21lIiwKICAgICAgICAgbG9hZGluZ3MgPSBUUlVFLCAKICAgICAgICAgbG9hZGluZ3MuY29sb3VyID0gYWxwaGEoImJsdWUiLCAwLjEpLAogICAgICAgICBsb2FkaW5ncy5sYWJlbCA9IFRSVUUsIAogICAgICAgICBsb2FkaW5ncy5sYWJlbC5zaXplID0gMiwKICAgICAgICAgbG9hZGluZ3MubGFiZWwuY29sb3VyID0gYWxwaGEoInJlZCIsIDAuNyksCiAgICAgICAgIHggPSAzLAogICAgICAgICB5ID0gNCkKYGBgICAKICAgCiMjIFVNQVAgICAgCiMjIyBDYWxjdWxhdGUgVU1BUCAgIApgYGB7cn0KdW1hcCA9IHVtYXAocGNhX2RhdGEsIAogICAgICAgICAgICBuX25laWdoYm9ycyA9IDE1LAogICAgICAgICAgICBtaW5fZGlzdCA9IDAuMSwKICAgICAgICAgICAgc2NhbGUgPSAiWiIpCmNvbG5hbWVzKHVtYXApID0gYygidW1hcF8xIiwgInVtYXBfMiIpCnVtYXBfZGF0YSA9IGNiaW5kKHBjYV9kYXRhX2NvbXBsZXRlLCB1bWFwKQpgYGAgICAKICAgCiMjIFBsb3QKYGBge3J9CmdncGxvdCh1bWFwX2RhdGEsIGFlcyh4ID0gdW1hcF8xLCB5ID0gdW1hcF8yLCBjb2xvciA9IGJpbm5lZF9vdXRjb21lKSkgKwogIGdlb21fcG9pbnQoKSArCiAgc3RhdF9lbGxpcHNlKCkKYGBgClRoaXMgZG9lc24ndCBzZWVtIHRvIGFkZCBtdWNoLiAgIAogICAKIyMjIEp1c3QgRDAgc2FtcGxlcyAgIApgYGB7cn0KY2xpbmljYWxfZGF5MCA9IG9ubHlfbWV0YWRhdGEgJT4lIAogIHVuaXF1ZSgpICU+JSAjb2RkbHkgdGhlcmUgaXMgZHVwbGljYXRpb24KICBkcGx5cjo6ZmlsdGVyKCFpcy5uYShCQUxfb3JkZXJfZGF0ZSkgJiB2ZW50aWxhdG9yX2RheXMgPT0gMCkgJT4lICNyZW1vdmUgc2FtcGxlcyB3aXRob3V0IEJBTCBpbmZvCiAgbXV0YXRlKHNhbXBsZV9pZCA9IHBhc3RlKGlyX2lkLCBCQUxfb3JkZXJfdGltZXN0YW1wLCBzZXAgPSAiXyIpKSAlPiUgCiAgc2VsZWN0KGMoc2FtcGxlX2lkLAogICAgICAgICAgIEFic29sdXRlX05ldXRyb3BoaWxzLAogICAgICAgICAgIFdISVRFX0JMT09EX0NFTExfQ09VTlQ6RF9ESU1FUiwgCiAgICAgICAgICAgbWF4X2RhaWx5X3RlbXApKSAlPiUgCiAgICBjb2x1bW5fdG9fcm93bmFtZXModmFyID0gInNhbXBsZV9pZCIpICU+JSAKICBuYS5vbWl0KCkKa2VlcF9jb2xzID0gYXBwbHkoY2xpbmljYWxfZGF5MCwgMiwgc2FmZV9jb2xzKQpwY2FfZGF0YSA9IGNsaW5pY2FsX2RheTBbLCBrZWVwX2NvbHNdCgpwY2FfZGF0YV9jb21wbGV0ZSA9IG9ubHlfbWV0YWRhdGEgJT4lIAogIHVuaXF1ZSgpICU+JQogIG11dGF0ZShzYW1wbGVfaWQgPSBwYXN0ZShpcl9pZCwgQkFMX29yZGVyX3RpbWVzdGFtcCwgc2VwID0gIl8iKSkgJT4lIAogIGRwbHlyOjpmaWx0ZXIoc2FtcGxlX2lkICVpbiUgcm93bmFtZXMocGNhX2RhdGEpKSAlPiUgCiAgY29sdW1uX3RvX3Jvd25hbWVzKHZhciA9ICJzYW1wbGVfaWQiKQoKI25lZWQgdG8gdXNlIGZvcm11bGEgaW50ZXJmYWNlIHRvIGRlYWwgd2l0aCBOQXMgYmVjYXVzZSBub3RoaW5nIGlzIGV2ZXIgZWFzeQpmb3JtdWxhID0gcGFzdGUwKCJ+ICIsCiAgICAgICAgICAgICAgICAgcGFzdGUoY29sbmFtZXMocGNhX2RhdGEpLCBjb2xsYXBzZSA9ICIrIikpCmZvcm11bGEgPSBhcy5mb3JtdWxhKGZvcm11bGEpCnBjYSA9IHByY29tcChmb3JtdWxhID0gZm9ybXVsYSwKICAgICAgICAgICAgIGRhdGEgPSBwY2FfZGF0YSwgCiAgICAgICAgICAgICBzY2FsZS4gPSBULAogICAgICAgICAgICAgbmEuYWN0aW9uID0gbmEub21pdCkKCmF1dG9wbG90KHBjYSwgCiAgICAgICAgIGRhdGEgPSBwY2FfZGF0YV9jb21wbGV0ZSwgCiAgICAgICAgIGNvbG91ciA9ICJiaW5uZWRfb3V0Y29tZSIsCiAgICAgICAgIGxvYWRpbmdzID0gVFJVRSwgCiAgICAgICAgIGxvYWRpbmdzLmNvbG91ciA9IGFscGhhKCJibHVlIiwgMC4xKSwKICAgICAgICAgbG9hZGluZ3MubGFiZWwgPSBUUlVFLCAKICAgICAgICAgbG9hZGluZ3MubGFiZWwuc2l6ZSA9IDIsCiAgICAgICAgIGxvYWRpbmdzLmxhYmVsLmNvbG91ciA9IGFscGhhKCJyZWQiLCAwLjcpLAogICAgICAgICB4ID0gMSwKICAgICAgICAgeSA9IDIpCmF1dG9wbG90KHBjYSwgCiAgICAgICAgIGRhdGEgPSBwY2FfZGF0YV9jb21wbGV0ZSwgCiAgICAgICAgIGNvbG91ciA9ICJiaW5uZWRfb3V0Y29tZSIsCiAgICAgICAgIGxvYWRpbmdzID0gVFJVRSwgCiAgICAgICAgIGxvYWRpbmdzLmNvbG91ciA9IGFscGhhKCJibHVlIiwgMC4xKSwKICAgICAgICAgbG9hZGluZ3MubGFiZWwgPSBUUlVFLCAKICAgICAgICAgbG9hZGluZ3MubGFiZWwuc2l6ZSA9IDIsCiAgICAgICAgIGxvYWRpbmdzLmxhYmVsLmNvbG91ciA9IGFscGhhKCJyZWQiLCAwLjcpLAogICAgICAgICB4ID0gMiwKICAgICAgICAgeSA9IDMpCmF1dG9wbG90KHBjYSwgCiAgICAgICAgIGRhdGEgPSBwY2FfZGF0YV9jb21wbGV0ZSwgCiAgICAgICAgIGNvbG91ciA9ICJiaW5uZWRfb3V0Y29tZSIsCiAgICAgICAgIGxvYWRpbmdzID0gVFJVRSwgCiAgICAgICAgIGxvYWRpbmdzLmNvbG91ciA9IGFscGhhKCJibHVlIiwgMC4xKSwKICAgICAgICAgbG9hZGluZ3MubGFiZWwgPSBUUlVFLCAKICAgICAgICAgbG9hZGluZ3MubGFiZWwuc2l6ZSA9IDIsCiAgICAgICAgIGxvYWRpbmdzLmxhYmVsLmNvbG91ciA9IGFscGhhKCJyZWQiLCAwLjcpLAogICAgICAgICB4ID0gMywKICAgICAgICAgeSA9IDQpCmBgYAoKTm90IGFjdHVhbGx5IHZlcnkgZGlmZmVyZW50IGZyb20gY29tcGxldGUgZGF0YXNldC4gICAKICAgCiMjIFdpdGggZmxvdyBkYXRhICAgCiMjIyBBbGwgc2FtcGxlcyAgIApgYGB7cn0KZmxvd19wY2EgPSBkYXRhICU+JSAKICB1bmlxdWUoKSAlPiUgI29kZGx5IHRoZXJlIGlzIGR1cGxpY2F0aW9uCiAgZHBseXI6OmZpbHRlcighaXMubmEobWVyZ2VfZGF0ZSkpICU+JSAjcmVtb3ZlIHNhbXBsZXMgd2l0aG91dCBCQUwgaW5mbwogIG11dGF0ZShzYW1wbGVfaWQgPSBwYXN0ZShpcl9pZCwgQkFMX29yZGVyX3RpbWVzdGFtcCwgc2VwID0gIl8iKSkgJT4lIAogIHNlbGVjdChjKFNhbXBsZSwKICAgICAgICAgICBBYnNvbHV0ZV9OZXV0cm9waGlscywKICAgICAgICAgICBXSElURV9CTE9PRF9DRUxMX0NPVU5UOkRfRElNRVIsIAogICAgICAgICAgIG1heF9kYWlseV90ZW1wLAogICAgICAgICAgIHBlcmNlbnRfQ0Q0X3RvdGFsOnBlcmNlbnRfb3RoZXJzKSkgJT4lIAogICAgY29sdW1uX3RvX3Jvd25hbWVzKHZhciA9ICJTYW1wbGUiKQoKa2VlcF9jb2xzID0gYXBwbHkoZmxvd19wY2EsIDIsIHNhZmVfY29scykKcGNhX2RhdGEgPSBuYS5vbWl0KGZsb3dfcGNhWywga2VlcF9jb2xzXSkKCiNuZWVkIHRvIHVzZSBmb3JtdWxhIGludGVyZmFjZSB0byBkZWFsIHdpdGggTkFzIGJlY2F1c2Ugbm90aGluZyBpcyBldmVyIGVhc3kKZm9ybXVsYSA9IHBhc3RlMCgifiAiLAogICAgICAgICAgICAgICAgIHBhc3RlKGNvbG5hbWVzKHBjYV9kYXRhKSwgY29sbGFwc2UgPSAiKyIpKQpmb3JtdWxhID0gYXMuZm9ybXVsYShmb3JtdWxhKQpwY2EgPSBwcmNvbXAoZm9ybXVsYSA9IGZvcm11bGEsCiAgICAgICAgICAgICBkYXRhID0gcGNhX2RhdGEsIAogICAgICAgICAgICAgc2NhbGUuID0gVCwKICAgICAgICAgICAgIG5hLmFjdGlvbiA9IG5hLm9taXQpCgpwY2FfZGF0YV9jb21wbGV0ZSA9IGRhdGEgJT4lIAogIHVuaXF1ZSgpICU+JQogIGRwbHlyOjpmaWx0ZXIoU2FtcGxlICVpbiUgcm93bmFtZXMocGNhX2RhdGEpKSAlPiUgCiAgY29sdW1uX3RvX3Jvd25hbWVzKHZhciA9ICJTYW1wbGUiKQoKYXV0b3Bsb3QocGNhLCAKICAgICAgICAgZGF0YSA9IHBjYV9kYXRhX2NvbXBsZXRlLCAKICAgICAgICAgY29sb3VyID0gImJpbm5lZF9vdXRjb21lIiwKICAgICAgICAgbG9hZGluZ3MgPSBUUlVFLCAKICAgICAgICAgbG9hZGluZ3MuY29sb3VyID0gYWxwaGEoImJsdWUiLCAwLjEpLAogICAgICAgICBsb2FkaW5ncy5sYWJlbCA9IFRSVUUsIAogICAgICAgICBsb2FkaW5ncy5sYWJlbC5zaXplID0gMiwKICAgICAgICAgbG9hZGluZ3MubGFiZWwuY29sb3VyID0gYWxwaGEoInJlZCIsIDAuNyksCiAgICAgICAgIHggPSAxLAogICAgICAgICB5ID0gMikKYXV0b3Bsb3QocGNhLCAKICAgICAgICAgZGF0YSA9IHBjYV9kYXRhX2NvbXBsZXRlLCAKICAgICAgICAgY29sb3VyID0gImJpbm5lZF9vdXRjb21lIiwKICAgICAgICAgbG9hZGluZ3MgPSBUUlVFLCAKICAgICAgICAgbG9hZGluZ3MuY29sb3VyID0gYWxwaGEoImJsdWUiLCAwLjEpLAogICAgICAgICBsb2FkaW5ncy5sYWJlbCA9IFRSVUUsIAogICAgICAgICBsb2FkaW5ncy5sYWJlbC5zaXplID0gMiwKICAgICAgICAgbG9hZGluZ3MubGFiZWwuY29sb3VyID0gYWxwaGEoInJlZCIsIDAuNyksCiAgICAgICAgIHggPSAyLAogICAgICAgICB5ID0gMykKYXV0b3Bsb3QocGNhLCAKICAgICAgICAgZGF0YSA9IHBjYV9kYXRhX2NvbXBsZXRlLCAKICAgICAgICAgY29sb3VyID0gImJpbm5lZF9vdXRjb21lIiwKICAgICAgICAgbG9hZGluZ3MgPSBUUlVFLCAKICAgICAgICAgbG9hZGluZ3MuY29sb3VyID0gYWxwaGEoImJsdWUiLCAwLjEpLAogICAgICAgICBsb2FkaW5ncy5sYWJlbCA9IFRSVUUsIAogICAgICAgICBsb2FkaW5ncy5sYWJlbC5zaXplID0gMiwKICAgICAgICAgbG9hZGluZ3MubGFiZWwuY29sb3VyID0gYWxwaGEoInJlZCIsIDAuNyksCiAgICAgICAgIHggPSAzLAogICAgICAgICB5ID0gNCkKYGBgCgpEYXRhIGlzIHN0aWxsIHRvbyBzcGFyc2UgdG8gcmVhbGx5IGxvb2sgaW50byB0aGlzLiAgIAogICAKIyMgSGllcmFyY2hpY2FsIGNsdXN0ZXJpbmcgICAKIyMjIEFsbCBkYXlzICAgCmBgYHtyfQpoZWF0bWFwX2RhdGEgPSBvbmx5X21ldGFkYXRhICU+JSAKICB1bmlxdWUoKSAlPiUgI29kZGx5IHRoZXJlIGlzIGR1cGxpY2F0aW9uCiAgZHBseXI6OmZpbHRlcighaXMubmEoQkFMX29yZGVyX2RhdGUpKSAlPiUgI3JlbW92ZSBzYW1wbGVzIHdpdGhvdXQgQkFMIGluZm8KICBtdXRhdGUoc2FtcGxlX2lkID0gcGFzdGUoaXJfaWQsIEJBTF9vcmRlcl90aW1lc3RhbXAsIHNlcCA9ICJfIikpICU+JSAKICBzZWxlY3QoYyhzYW1wbGVfaWQsCiAgICAgICAgICAgQWJzb2x1dGVfTmV1dHJvcGhpbHMsCiAgICAgICAgICAgV0hJVEVfQkxPT0RfQ0VMTF9DT1VOVDpEX0RJTUVSLCAKICAgICAgICAgICBtYXhfZGFpbHlfdGVtcCkpICU+JSAKICAgIGNvbHVtbl90b19yb3duYW1lcyh2YXIgPSAic2FtcGxlX2lkIikKCmhlYXRtYXBfbWV0YWRhdGEgPSBvbmx5X21ldGFkYXRhICU+JSAKICB1bmlxdWUoKSAlPiUKICBtdXRhdGUoc2FtcGxlX2lkID0gcGFzdGUoaXJfaWQsIEJBTF9vcmRlcl90aW1lc3RhbXAsIHNlcCA9ICJfIikpICU+JSAKICBkcGx5cjo6ZmlsdGVyKHNhbXBsZV9pZCAlaW4lIHJvd25hbWVzKGhlYXRtYXBfZGF0YSkpICU+JSAKICBzZWxlY3Qoc2FtcGxlX2lkLCB2ZW50aWxhdG9yX2RheXMsIGJpbm5lZF9vdXRjb21lKSAlPiUgCiAgY29sdW1uX3RvX3Jvd25hbWVzKHZhciA9ICJzYW1wbGVfaWQiKQoKcGhlYXRtYXAoaGVhdG1hcF9kYXRhLCAKICAgICAgICAgY2x1c3Rlcl9yb3dzID0gVCwKICAgICAgICAgY2x1c3Rlcl9jb2xzID0gVCwKICAgICAgICAgY2x1c3RlcmluZ19tZXRob2QgPSAid2FyZC5EMiIsCiAgICAgICAgIGFubm90YXRpb25fcm93ID0gaGVhdG1hcF9tZXRhZGF0YSwKICAgICAgICAgc2NhbGUgPSAiY29sdW1uIiwKICAgICAgICAgYW5nbGVfY29sID0gNDUsCiAgICAgICAgIGJyZWFrcyA9IHNlcSgtNSwgNSwgbGVuZ3RoLm91dD0xMDEpLAogICAgICAgICBjb2xvciA9IGNvbG9yUmFtcFBhbGV0dGUocmV2KGJyZXdlci5wYWwobiA9IDcsIG5hbWUgPSAiUmRCdSIpKSkoMTAxKSkKYGBgCgo=